opencloudtool 0.6.0__tar.gz → 0.7.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/Cargo.lock +95 -19
  2. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/Cargo.toml +9 -8
  3. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/PKG-INFO +1 -1
  4. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/README.md +4 -0
  5. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/aws/types.rs +146 -17
  6. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/infra/graph.rs +45 -134
  7. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/infra/resource.rs +12 -12
  8. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-ctl-sdk/Cargo.toml +1 -1
  9. {opencloudtool-0.6.0/crates/oct-orchestrator → opencloudtool-0.7.0/crates/oct-ctl-sdk}/README.md +4 -0
  10. {opencloudtool-0.6.0/crates/oct-ctl-sdk → opencloudtool-0.7.0/crates/oct-orchestrator}/README.md +4 -0
  11. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-orchestrator/src/lib.rs +14 -30
  12. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-py/uv.lock +1 -1
  13. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/pyproject.toml +1 -1
  14. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/README.md +0 -0
  15. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/Cargo.toml +0 -0
  16. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/aws/client.rs +0 -0
  17. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/aws/mod.rs +0 -0
  18. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/aws/resource.rs +0 -0
  19. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/infra/mod.rs +0 -0
  20. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/infra/state.rs +0 -0
  21. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/lib.rs +0 -0
  22. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-cloud/src/resource.rs +0 -0
  23. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-ctl-sdk/src/lib.rs +0 -0
  24. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-orchestrator/Cargo.toml +0 -0
  25. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-orchestrator/src/backend.rs +0 -0
  26. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-orchestrator/src/config.rs +0 -0
  27. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-orchestrator/src/scheduler.rs +0 -0
  28. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-orchestrator/src/user_state.rs +0 -0
  29. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-py/.python-version +0 -0
  30. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-py/Cargo.toml +0 -0
  31. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-py/README.md +0 -0
  32. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-py/python/opencloudtool/__init__.py +0 -0
  33. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-py/python/opencloudtool/py_api.py +0 -0
  34. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/crates/oct-py/src/lib.rs +0 -0
  35. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/python/opencloudtool/__init__.py +0 -0
  36. {opencloudtool-0.6.0 → opencloudtool-0.7.0}/python/opencloudtool/py_api.py +0 -0
@@ -82,6 +82,48 @@ dependencies = [
82
82
  "windows-sys 0.59.0",
83
83
  ]
84
84
 
85
+ [[package]]
86
+ name = "askama"
87
+ version = "0.14.0"
88
+ source = "registry+https://github.com/rust-lang/crates.io-index"
89
+ checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
90
+ dependencies = [
91
+ "askama_derive",
92
+ "itoa",
93
+ "percent-encoding",
94
+ "serde",
95
+ "serde_json",
96
+ ]
97
+
98
+ [[package]]
99
+ name = "askama_derive"
100
+ version = "0.14.0"
101
+ source = "registry+https://github.com/rust-lang/crates.io-index"
102
+ checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
103
+ dependencies = [
104
+ "askama_parser",
105
+ "basic-toml",
106
+ "memchr",
107
+ "proc-macro2",
108
+ "quote",
109
+ "rustc-hash 2.1.1",
110
+ "serde",
111
+ "serde_derive",
112
+ "syn",
113
+ ]
114
+
115
+ [[package]]
116
+ name = "askama_parser"
117
+ version = "0.14.0"
118
+ source = "registry+https://github.com/rust-lang/crates.io-index"
119
+ checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
120
+ dependencies = [
121
+ "memchr",
122
+ "serde",
123
+ "serde_derive",
124
+ "winnow",
125
+ ]
126
+
85
127
  [[package]]
86
128
  name = "assert-json-diff"
87
129
  version = "2.0.2"
@@ -651,9 +693,9 @@ dependencies = [
651
693
 
652
694
  [[package]]
653
695
  name = "axum"
654
- version = "0.8.6"
696
+ version = "0.8.7"
655
697
  source = "registry+https://github.com/rust-lang/crates.io-index"
656
- checksum = "8a18ed336352031311f4e0b4dd2ff392d4fbb370777c9d18d7fc9d7359f73871"
698
+ checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425"
657
699
  dependencies = [
658
700
  "axum-core",
659
701
  "bytes",
@@ -735,6 +777,15 @@ version = "1.8.0"
735
777
  source = "registry+https://github.com/rust-lang/crates.io-index"
736
778
  checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
737
779
 
780
+ [[package]]
781
+ name = "basic-toml"
782
+ version = "0.1.10"
783
+ source = "registry+https://github.com/rust-lang/crates.io-index"
784
+ checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
785
+ dependencies = [
786
+ "serde",
787
+ ]
788
+
738
789
  [[package]]
739
790
  name = "bindgen"
740
791
  version = "0.69.5"
@@ -752,7 +803,7 @@ dependencies = [
752
803
  "proc-macro2",
753
804
  "quote",
754
805
  "regex",
755
- "rustc-hash",
806
+ "rustc-hash 1.1.0",
756
807
  "shlex",
757
808
  "syn",
758
809
  "which",
@@ -879,9 +930,9 @@ dependencies = [
879
930
 
880
931
  [[package]]
881
932
  name = "clap"
882
- version = "4.5.51"
933
+ version = "4.5.53"
883
934
  source = "registry+https://github.com/rust-lang/crates.io-index"
884
- checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5"
935
+ checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8"
885
936
  dependencies = [
886
937
  "clap_builder",
887
938
  "clap_derive",
@@ -889,9 +940,9 @@ dependencies = [
889
940
 
890
941
  [[package]]
891
942
  name = "clap_builder"
892
- version = "4.5.51"
943
+ version = "4.5.53"
893
944
  source = "registry+https://github.com/rust-lang/crates.io-index"
894
- checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a"
945
+ checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00"
895
946
  dependencies = [
896
947
  "anstream",
897
948
  "anstyle",
@@ -2078,9 +2129,9 @@ dependencies = [
2078
2129
 
2079
2130
  [[package]]
2080
2131
  name = "mockall"
2081
- version = "0.13.1"
2132
+ version = "0.14.0"
2082
2133
  source = "registry+https://github.com/rust-lang/crates.io-index"
2083
- checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2"
2134
+ checksum = "f58d964098a5f9c6b63d0798e5372fd04708193510a7af313c22e9f29b7b620b"
2084
2135
  dependencies = [
2085
2136
  "cfg-if",
2086
2137
  "downcast",
@@ -2092,9 +2143,9 @@ dependencies = [
2092
2143
 
2093
2144
  [[package]]
2094
2145
  name = "mockall_derive"
2095
- version = "0.13.1"
2146
+ version = "0.14.0"
2096
2147
  source = "registry+https://github.com/rust-lang/crates.io-index"
2097
- checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898"
2148
+ checksum = "ca41ce716dda6a9be188b385aa78ee5260fc25cd3802cb2a8afdc6afbe6b6dbf"
2098
2149
  dependencies = [
2099
2150
  "cfg-if",
2100
2151
  "proc-macro2",
@@ -2194,7 +2245,7 @@ dependencies = [
2194
2245
 
2195
2246
  [[package]]
2196
2247
  name = "oct-cli"
2197
- version = "0.6.0"
2248
+ version = "0.7.0"
2198
2249
  dependencies = [
2199
2250
  "assert_cmd",
2200
2251
  "clap",
@@ -2206,7 +2257,7 @@ dependencies = [
2206
2257
 
2207
2258
  [[package]]
2208
2259
  name = "oct-cloud"
2209
- version = "0.6.0"
2260
+ version = "0.7.0"
2210
2261
  dependencies = [
2211
2262
  "aws-config",
2212
2263
  "aws-sdk-ec2",
@@ -2226,7 +2277,7 @@ dependencies = [
2226
2277
 
2227
2278
  [[package]]
2228
2279
  name = "oct-ctl"
2229
- version = "0.6.0"
2280
+ version = "0.7.0"
2230
2281
  dependencies = [
2231
2282
  "axum",
2232
2283
  "log",
@@ -2242,7 +2293,7 @@ dependencies = [
2242
2293
 
2243
2294
  [[package]]
2244
2295
  name = "oct-ctl-sdk"
2245
- version = "0.6.0"
2296
+ version = "0.7.0"
2246
2297
  dependencies = [
2247
2298
  "log",
2248
2299
  "mockito",
@@ -2254,7 +2305,7 @@ dependencies = [
2254
2305
 
2255
2306
  [[package]]
2256
2307
  name = "oct-orchestrator"
2257
- version = "0.6.0"
2308
+ version = "0.7.0"
2258
2309
  dependencies = [
2259
2310
  "async-trait",
2260
2311
  "log",
@@ -2270,9 +2321,25 @@ dependencies = [
2270
2321
  "toml",
2271
2322
  ]
2272
2323
 
2324
+ [[package]]
2325
+ name = "oct-platform"
2326
+ version = "0.7.0"
2327
+ dependencies = [
2328
+ "askama",
2329
+ "axum",
2330
+ "reqwest",
2331
+ "serde",
2332
+ "serde_json",
2333
+ "tokio",
2334
+ "toml",
2335
+ "tower-http",
2336
+ "tracing",
2337
+ "tracing-subscriber",
2338
+ ]
2339
+
2273
2340
  [[package]]
2274
2341
  name = "oct-py"
2275
- version = "0.6.0"
2342
+ version = "0.7.0"
2276
2343
  dependencies = [
2277
2344
  "env_logger",
2278
2345
  "log",
@@ -2852,6 +2919,12 @@ version = "1.1.0"
2852
2919
  source = "registry+https://github.com/rust-lang/crates.io-index"
2853
2920
  checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
2854
2921
 
2922
+ [[package]]
2923
+ name = "rustc-hash"
2924
+ version = "2.1.1"
2925
+ source = "registry+https://github.com/rust-lang/crates.io-index"
2926
+ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
2927
+
2855
2928
  [[package]]
2856
2929
  name = "rustc_version"
2857
2930
  version = "0.4.1"
@@ -3586,9 +3659,9 @@ dependencies = [
3586
3659
 
3587
3660
  [[package]]
3588
3661
  name = "tower-http"
3589
- version = "0.6.6"
3662
+ version = "0.6.7"
3590
3663
  source = "registry+https://github.com/rust-lang/crates.io-index"
3591
- checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2"
3664
+ checksum = "9cf146f99d442e8e68e585f5d798ccd3cad9a7835b917e09728880a862706456"
3592
3665
  dependencies = [
3593
3666
  "bitflags",
3594
3667
  "bytes",
@@ -4213,6 +4286,9 @@ name = "winnow"
4213
4286
  version = "0.7.13"
4214
4287
  source = "registry+https://github.com/rust-lang/crates.io-index"
4215
4288
  checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf"
4289
+ dependencies = [
4290
+ "memchr",
4291
+ ]
4216
4292
 
4217
4293
  [[package]]
4218
4294
  name = "wit-bindgen-rt"
@@ -1,5 +1,5 @@
1
1
  [workspace.package]
2
- version = "0.6.0"
2
+ version = "0.7.0"
3
3
  authors = ["opencloudtool Contributors"]
4
4
  categories = ["command-line-utilities"]
5
5
  documentation = "https://opencloudtool.com/docs"
@@ -25,11 +25,12 @@ members = ["crates/*"]
25
25
  resolver = "3"
26
26
 
27
27
  [workspace.dependencies]
28
- oct-cloud = { package = "oct-cloud", path = "crates/oct-cloud", version = "0.6.0" }
29
- oct-orchestrator = { package = "oct-orchestrator", path = "crates/oct-orchestrator", version = "0.6.0" }
30
- oct-ctl-sdk = { package = "oct-ctl-sdk", path = "crates/oct-ctl-sdk", version = "0.6.0" }
28
+ oct-cloud = { package = "oct-cloud", path = "crates/oct-cloud", version = "0.7.0" }
29
+ oct-orchestrator = { package = "oct-orchestrator", path = "crates/oct-orchestrator", version = "0.7.0" }
30
+ oct-ctl-sdk = { package = "oct-ctl-sdk", path = "crates/oct-ctl-sdk", version = "0.7.0" }
31
31
 
32
32
  assert_cmd = "2.1.1"
33
+ askama = "0.14.0"
33
34
  async-trait = "0.1.89"
34
35
  aws-config = "1.8.3"
35
36
  aws-sdk-ec2 = "1.154.0"
@@ -37,9 +38,9 @@ aws-sdk-ecr = "1.87.0"
37
38
  aws-sdk-iam = "1.83.0"
38
39
  aws-sdk-route53 = "1.88.0"
39
40
  aws-sdk-s3 = "1.100.0"
40
- axum = "0.8.6"
41
+ axum = "0.8.7"
41
42
  base64 = "0.22.1"
42
- clap = { version = "4.5.51", features = ["derive"] }
43
+ clap = { version = "4.5.53", features = ["derive"] }
43
44
  petgraph = "0.8.3"
44
45
  predicates = "3.1.3"
45
46
  serde = "1.0.228"
@@ -48,7 +49,7 @@ serde_json = "1.0.145"
48
49
  tempfile = "3.23.0"
49
50
  tera = { git = "https://github.com/minev-dev/tera.git", rev = "1e36d2f8ba66833ce9ad2b46044e21f8240b5299", version = "1.20.0" } # Contains custom logic to render variables ignoring unknown variables
50
51
  tokio = { version = "1.48.0", features = ["full"] }
51
- mockall = "0.13.1"
52
+ mockall = "0.14.0"
52
53
  mockito = "1.7.0"
53
54
  pyo3 = { version = "0.27.1", features = ["extension-module"] }
54
55
  uuid = { version = "1.18.1", features = ["v4"] }
@@ -57,7 +58,7 @@ env_logger = "0.11.6"
57
58
  toml = "0.9.8"
58
59
  reqwest = { version = "0.12.24", features = ["json"] }
59
60
  tower = "0.5.2"
60
- tower-http = { version = "0.6.4", features = ["trace"] }
61
+ tower-http = { version = "0.6.7", features = ["trace"] }
61
62
  tracing = "0.1"
62
63
  tracing-subscriber = { version = "0.3" }
63
64
  grcov = "0.8.20"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencloudtool
3
- Version: 0.6.0
3
+ Version: 0.7.0
4
4
  Requires-Python: >=3.8
5
5
  Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
6
6
 
@@ -230,3 +230,7 @@ Total: $92 per month
230
230
  - 1 EC2 [t4g.medium](https://aws.amazon.com/ec2/pricing/on-demand/) instance ($0.0336 per hour): $25.5 per month
231
231
 
232
232
  Total: $25.5 per month
233
+
234
+ ## Repo stats
235
+
236
+ ![Alt](https://repobeats.axiom.co/api/embed/7127395110cea0828bf52367026a5768d9c016e8.svg "Repobeats analytics image")
@@ -74,28 +74,81 @@ pub struct InstanceInfo {
74
74
 
75
75
  #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
76
76
  pub enum InstanceType {
77
- T2Micro,
77
+ T3Nano,
78
+ T3Micro,
79
+ T3Small,
78
80
  T3Medium,
81
+ T3Large,
82
+ T3Xlarge,
83
+ T32xlarge,
79
84
  }
80
85
 
81
86
  impl InstanceType {
82
87
  pub fn as_str(&self) -> &str {
83
88
  match self {
84
- InstanceType::T2Micro => "t2.micro",
89
+ InstanceType::T3Nano => "t3.nano",
90
+ InstanceType::T3Micro => "t3.micro",
91
+ InstanceType::T3Small => "t3.small",
85
92
  InstanceType::T3Medium => "t3.medium",
93
+ InstanceType::T3Large => "t3.large",
94
+ InstanceType::T3Xlarge => "t3.xlarge",
95
+ InstanceType::T32xlarge => "t3.2xlarge",
86
96
  }
87
97
  }
88
98
 
99
+ /// Tries to get the smallest possible instance type for to fit requested resources
100
+ // NOTE: The instances list must be sorted by size from smallest to largest
101
+ pub fn from_resources(cpus: u32, memory: u64) -> Option<Self> {
102
+ let instances = [
103
+ Self::T3Nano,
104
+ Self::T3Micro,
105
+ Self::T3Small,
106
+ Self::T3Medium,
107
+ Self::T3Large,
108
+ Self::T3Xlarge,
109
+ Self::T32xlarge,
110
+ ];
111
+
112
+ for instance in instances {
113
+ let info = instance.get_info();
114
+ if cpus <= info.cpus && memory <= info.memory {
115
+ return Some(instance);
116
+ }
117
+ }
118
+
119
+ None
120
+ }
121
+
89
122
  pub fn get_info(&self) -> InstanceInfo {
90
123
  match self {
91
- InstanceType::T2Micro => InstanceInfo {
92
- cpus: 1000,
124
+ Self::T3Nano => InstanceInfo {
125
+ cpus: 2000,
126
+ memory: 512,
127
+ },
128
+ Self::T3Micro => InstanceInfo {
129
+ cpus: 2000,
93
130
  memory: 1024,
94
131
  },
95
- InstanceType::T3Medium => InstanceInfo {
132
+ Self::T3Small => InstanceInfo {
133
+ cpus: 2000,
134
+ memory: 2048,
135
+ },
136
+ Self::T3Medium => InstanceInfo {
96
137
  cpus: 2000,
97
138
  memory: 4096,
98
139
  },
140
+ Self::T3Large => InstanceInfo {
141
+ cpus: 2000,
142
+ memory: 8192,
143
+ },
144
+ Self::T3Xlarge => InstanceInfo {
145
+ cpus: 4000,
146
+ memory: 16384,
147
+ },
148
+ Self::T32xlarge => InstanceInfo {
149
+ cpus: 8000,
150
+ memory: 32768,
151
+ },
99
152
  }
100
153
  }
101
154
  }
@@ -108,8 +161,13 @@ impl From<&str> for InstanceType {
108
161
  /// Panics if the string is not a valid instance type.
109
162
  fn from(value: &str) -> Self {
110
163
  match value {
111
- "t2.micro" => InstanceType::T2Micro,
112
- "t3.medium" => InstanceType::T3Medium,
164
+ "t3.nano" => Self::T3Nano,
165
+ "t3.micro" => Self::T3Micro,
166
+ "t3.small" => Self::T3Small,
167
+ "t3.medium" => Self::T3Medium,
168
+ "t3.large" => Self::T3Large,
169
+ "t3.xlarge" => Self::T3Xlarge,
170
+ "t3.2xlarge" => Self::T32xlarge,
113
171
  _ => panic!("Invalid instance type: {value}"),
114
172
  }
115
173
  }
@@ -186,32 +244,32 @@ mod tests {
186
244
 
187
245
  #[test]
188
246
  fn test_instance_type_as_str() {
189
- assert_eq!(InstanceType::T2Micro.as_str(), "t2.micro");
190
- assert_eq!(InstanceType::T3Medium.as_str(), "t3.medium");
247
+ assert_eq!(InstanceType::T3Nano.as_str(), "t3.nano");
248
+ assert_eq!(InstanceType::T32xlarge.as_str(), "t3.2xlarge");
191
249
  }
192
250
 
193
251
  #[test]
194
252
  fn test_instance_type_get_info() {
195
253
  assert_eq!(
196
- InstanceType::T2Micro.get_info(),
254
+ InstanceType::T3Nano.get_info(),
197
255
  InstanceInfo {
198
- cpus: 1000,
199
- memory: 1024
256
+ cpus: 2000,
257
+ memory: 512
200
258
  }
201
259
  );
202
260
  assert_eq!(
203
- InstanceType::T3Medium.get_info(),
261
+ InstanceType::T32xlarge.get_info(),
204
262
  InstanceInfo {
205
- cpus: 2000,
206
- memory: 4096
263
+ cpus: 8000,
264
+ memory: 32768
207
265
  }
208
266
  );
209
267
  }
210
268
 
211
269
  #[test]
212
270
  fn test_instance_type_from_str() {
213
- assert_eq!(InstanceType::from("t2.micro"), InstanceType::T2Micro);
214
- assert_eq!(InstanceType::from("t3.medium"), InstanceType::T3Medium);
271
+ assert_eq!(InstanceType::from("t3.nano"), InstanceType::T3Nano);
272
+ assert_eq!(InstanceType::from("t3.2xlarge"), InstanceType::T32xlarge);
215
273
  }
216
274
 
217
275
  #[test]
@@ -219,4 +277,75 @@ mod tests {
219
277
  fn test_instance_type_from_str_invalid() {
220
278
  let _ = InstanceType::from("invalid");
221
279
  }
280
+
281
+ #[test]
282
+ fn test_from_resources_fits_t3_nano_small_request() {
283
+ assert_eq!(
284
+ InstanceType::from_resources(500, 512),
285
+ Some(InstanceType::T3Nano)
286
+ );
287
+ }
288
+
289
+ #[test]
290
+ fn test_from_resources_fits_t3_nano_exact_request() {
291
+ assert_eq!(
292
+ InstanceType::from_resources(2000, 512),
293
+ Some(InstanceType::T3Nano)
294
+ );
295
+ }
296
+
297
+ #[test]
298
+ fn test_from_resources_fits_t3_micro_mem_overflow() {
299
+ assert_eq!(
300
+ InstanceType::from_resources(2000, 513),
301
+ Some(InstanceType::T3Micro)
302
+ );
303
+ }
304
+
305
+ #[test]
306
+ fn test_from_resources_fits_t3_medium_cpu_overflow() {
307
+ assert_eq!(
308
+ InstanceType::from_resources(2001, 8192),
309
+ Some(InstanceType::T3Xlarge)
310
+ );
311
+ }
312
+
313
+ #[test]
314
+ fn test_from_resources_fits_t3_xlarge_exact() {
315
+ assert_eq!(
316
+ InstanceType::from_resources(4000, 16384),
317
+ Some(InstanceType::T3Xlarge)
318
+ );
319
+ }
320
+
321
+ #[test]
322
+ fn test_from_resources_fits_t3_2xlarge_mem_overflow() {
323
+ assert_eq!(
324
+ InstanceType::from_resources(4000, 16385),
325
+ Some(InstanceType::T32xlarge)
326
+ );
327
+ }
328
+
329
+ #[test]
330
+ fn test_from_resources_fits_t3_2xlarge_exact_request() {
331
+ assert_eq!(
332
+ InstanceType::from_resources(8000, 32768),
333
+ Some(InstanceType::T32xlarge)
334
+ );
335
+ }
336
+
337
+ #[test]
338
+ fn test_from_resources_no_fit_cpu_overflow() {
339
+ assert_eq!(InstanceType::from_resources(8001, 32768), None);
340
+ }
341
+
342
+ #[test]
343
+ fn test_from_resources_no_fit_mem_overflow() {
344
+ assert_eq!(InstanceType::from_resources(8000, 32769), None);
345
+ }
346
+
347
+ #[test]
348
+ fn test_from_resources_no_fit_large_request() {
349
+ assert_eq!(InstanceType::from_resources(u32::MAX, u64::MAX), None);
350
+ }
222
351
  }
@@ -66,7 +66,6 @@ impl GraphManager {
66
66
  }
67
67
 
68
68
  pub fn get_spec_graph(
69
- number_of_instances: u32,
70
69
  instance_type: &types::InstanceType,
71
70
  domain_name: Option<String>,
72
71
  ) -> Graph<SpecNode, String> {
@@ -167,16 +166,11 @@ impl GraphManager {
167
166
  );
168
167
 
169
168
  // TODO: Add instance profile with instance role
170
- let mut instances = Vec::new();
171
- for _ in 0..number_of_instances {
172
- let instance_node = deps.add_node(SpecNode::Resource(ResourceSpecType::Vm(VmSpec {
173
- instance_type: instance_type.clone(),
174
- ami: String::from("ami-04dd23e62ed049936"),
175
- user_data: user_data.clone(),
176
- })));
177
-
178
- instances.push(instance_node);
179
- }
169
+ let vm = deps.add_node(SpecNode::Resource(ResourceSpecType::Vm(VmSpec {
170
+ instance_type: instance_type.clone(),
171
+ ami: String::from("ami-04dd23e62ed049936"),
172
+ user_data,
173
+ })));
180
174
 
181
175
  // Order of the edges matters in this implementation
182
176
  // Nodes within the same parent are traversed from
@@ -192,13 +186,12 @@ impl GraphManager {
192
186
  (igw_1, route_table_1, String::new()), // 7
193
187
  (route_table_1, subnet_1, String::new()), // 8
194
188
  (instance_role_1, instance_profile_1, String::new()), // 9
189
+ // VM
190
+ (subnet_1, vm, String::new()),
191
+ (instance_profile_1, vm, String::new()),
192
+ (security_group_1, vm, String::new()),
193
+ (ecr_1, vm, String::new()),
195
194
  ];
196
- for instance in &instances {
197
- edges.push((subnet_1, *instance, String::new()));
198
- edges.push((instance_profile_1, *instance, String::new()));
199
- edges.push((security_group_1, *instance, String::new()));
200
- edges.push((ecr_1, *instance, String::new()));
201
- }
202
195
 
203
196
  if let Some(domain_name) = domain_name {
204
197
  let hosted_zone = deps.add_node(SpecNode::Resource(ResourceSpecType::HostedZone(
@@ -211,17 +204,15 @@ impl GraphManager {
211
204
  // Insert at the first place to deploy it after all other root's children
212
205
  edges.insert(0, (root, hosted_zone, String::new()));
213
206
 
214
- for instance in instances {
215
- let dns_record = deps.add_node(SpecNode::Resource(ResourceSpecType::DnsRecord(
216
- DnsRecordSpec {
217
- record_type: types::RecordType::A,
218
- ttl: Some(3600),
219
- },
220
- )));
207
+ let dns_record = deps.add_node(SpecNode::Resource(ResourceSpecType::DnsRecord(
208
+ DnsRecordSpec {
209
+ record_type: types::RecordType::A,
210
+ ttl: Some(3600),
211
+ },
212
+ )));
221
213
 
222
- edges.push((instance, dns_record, String::new()));
223
- edges.push((hosted_zone, dns_record, String::new()));
224
- }
214
+ edges.push((vm, dns_record, String::new()));
215
+ edges.push((hosted_zone, dns_record, String::new()));
225
216
  }
226
217
 
227
218
  deps.extend_with_edges(&edges);
@@ -236,14 +227,14 @@ impl GraphManager {
236
227
  pub async fn deploy(
237
228
  &self,
238
229
  graph: &Graph<SpecNode, String>,
239
- ) -> Result<(Graph<Node, String>, Vec<Vm>, Option<Ecr>), Box<dyn std::error::Error>> {
230
+ ) -> Result<(Graph<Node, String>, Option<Vm>, Option<Ecr>), Box<dyn std::error::Error>> {
240
231
  let mut resource_graph = Graph::<Node, String>::new();
241
232
  let mut edges = vec![];
242
233
 
243
234
  let mut parents: HashMap<NodeIndex, Vec<NodeIndex>> = HashMap::new();
244
235
 
245
236
  let mut ecr: Option<Ecr> = None;
246
- let mut vms: Vec<Vm> = Vec::new();
237
+ let mut vm: Option<Vm> = None;
247
238
 
248
239
  let result = kahn_traverse(graph)?;
249
240
 
@@ -381,7 +372,7 @@ impl GraphManager {
381
372
 
382
373
  match output_vm {
383
374
  Ok(output_vm) => {
384
- vms.push(output_vm.clone());
375
+ vm = Some(output_vm.clone());
385
376
 
386
377
  Ok(Node::Resource(ResourceType::Vm(output_vm)))
387
378
  }
@@ -419,7 +410,7 @@ impl GraphManager {
419
410
 
420
411
  log::info!("Created graph {}", Dot::new(&resource_graph));
421
412
 
422
- Ok((resource_graph, vms, ecr))
413
+ Ok((resource_graph, vm, ecr))
423
414
  }
424
415
 
425
416
  /// Destroys resource graph
@@ -608,121 +599,43 @@ mod tests {
608
599
  #[test]
609
600
  fn test_get_spec_graph_with_one_instance_no_domain() {
610
601
  // Arrange
611
- let number_of_instances = 1;
612
- let instance_type = InstanceType::T2Micro;
613
- let domain_name = None;
614
-
615
- // Act
616
- let graph = GraphManager::get_spec_graph(number_of_instances, &instance_type, domain_name);
617
-
618
- // Assert
619
- let number_of_nodes = 9 + number_of_instances;
620
- let number_of_edges = 10 + 4 * number_of_instances;
621
- assert_eq!(graph.node_count(), number_of_nodes as usize);
622
- assert_eq!(graph.edge_count(), number_of_edges as usize);
623
-
624
- let vm_nodes_count = graph
625
- .raw_nodes()
626
- .iter()
627
- .filter(|node| matches!(&node.weight, SpecNode::Resource(ResourceSpecType::Vm(_))))
628
- .count();
629
- assert_eq!(vm_nodes_count, number_of_instances as usize);
630
- }
631
-
632
- #[test]
633
- fn test_get_spec_graph_with_multiple_instances_no_domain() {
634
- // Arrange
635
- let number_of_instances = 3;
636
- let instance_type = InstanceType::T2Micro;
602
+ let instance_type = InstanceType::T3Micro;
637
603
  let domain_name = None;
638
604
 
639
605
  // Act
640
- let graph = GraphManager::get_spec_graph(number_of_instances, &instance_type, domain_name);
606
+ let graph = GraphManager::get_spec_graph(&instance_type, domain_name);
641
607
 
642
608
  // Assert
643
- let number_of_nodes = 9 + number_of_instances;
644
- let number_of_edges = 10 + 4 * number_of_instances;
645
- assert_eq!(graph.node_count(), number_of_nodes as usize);
646
- assert_eq!(graph.edge_count(), number_of_edges as usize);
609
+ assert_eq!(graph.node_count(), 10);
610
+ assert_eq!(graph.edge_count(), 10 + 4);
647
611
 
648
612
  let vm_nodes_count = graph
649
613
  .raw_nodes()
650
614
  .iter()
651
615
  .filter(|node| matches!(&node.weight, SpecNode::Resource(ResourceSpecType::Vm(_))))
652
616
  .count();
653
- assert_eq!(vm_nodes_count, number_of_instances as usize);
617
+ assert_eq!(vm_nodes_count, 1);
654
618
  }
655
619
 
656
620
  #[test]
657
621
  fn test_get_spec_graph_with_one_instance_and_domain() {
658
622
  // Arrange
659
- let number_of_instances = 1;
660
- let instance_type = InstanceType::T2Micro;
661
- let domain_name = Some(String::from("example.com"));
662
-
663
- // Act
664
- let graph = GraphManager::get_spec_graph(number_of_instances, &instance_type, domain_name);
665
-
666
- // Assert
667
- let number_of_nodes = 10 + 2 * number_of_instances;
668
- let number_of_edges = 11 + 6 * number_of_instances;
669
- assert_eq!(graph.node_count(), number_of_nodes as usize);
670
- assert_eq!(graph.edge_count(), number_of_edges as usize);
671
-
672
- let vm_nodes_count = graph
673
- .raw_nodes()
674
- .iter()
675
- .filter(|node| matches!(&node.weight, SpecNode::Resource(ResourceSpecType::Vm(_))))
676
- .count();
677
- assert_eq!(vm_nodes_count, number_of_instances as usize);
678
-
679
- let hosted_zone_nodes_count = graph
680
- .raw_nodes()
681
- .iter()
682
- .filter(|node| {
683
- matches!(
684
- &node.weight,
685
- SpecNode::Resource(ResourceSpecType::HostedZone(_))
686
- )
687
- })
688
- .count();
689
- assert_eq!(hosted_zone_nodes_count, 1);
690
-
691
- let dns_record_nodes_count = graph
692
- .raw_nodes()
693
- .iter()
694
- .filter(|node| {
695
- matches!(
696
- &node.weight,
697
- SpecNode::Resource(ResourceSpecType::DnsRecord(_))
698
- )
699
- })
700
- .count();
701
- assert_eq!(dns_record_nodes_count, number_of_instances as usize);
702
- }
703
-
704
- #[test]
705
- fn test_get_spec_graph_with_multiple_instances_and_domain() {
706
- // Arrange
707
- let number_of_instances = 3;
708
- let instance_type = InstanceType::T2Micro;
623
+ let instance_type = InstanceType::T3Micro;
709
624
  let domain_name = Some(String::from("example.com"));
710
625
 
711
626
  // Act
712
- let graph = GraphManager::get_spec_graph(number_of_instances, &instance_type, domain_name);
627
+ let graph = GraphManager::get_spec_graph(&instance_type, domain_name);
713
628
 
714
629
  // Assert
715
- let number_of_nodes = 10 + 2 * number_of_instances;
716
- let number_of_edges = 11 + 6 * number_of_instances;
717
- assert_eq!(graph.node_count(), number_of_nodes as usize);
718
- assert_eq!(graph.edge_count(), number_of_edges as usize);
630
+ assert_eq!(graph.node_count(), 10 + 2);
631
+ assert_eq!(graph.edge_count(), 11 + 6);
719
632
 
720
633
  let vm_nodes_count = graph
721
634
  .raw_nodes()
722
635
  .iter()
723
636
  .filter(|node| matches!(&node.weight, SpecNode::Resource(ResourceSpecType::Vm(_))))
724
637
  .count();
725
- assert_eq!(vm_nodes_count, number_of_instances as usize);
638
+ assert_eq!(vm_nodes_count, 1);
726
639
 
727
640
  let hosted_zone_nodes_count = graph
728
641
  .raw_nodes()
@@ -746,18 +659,16 @@ mod tests {
746
659
  )
747
660
  })
748
661
  .count();
749
- assert_eq!(dns_record_nodes_count, number_of_instances as usize);
662
+ assert_eq!(dns_record_nodes_count, 1);
750
663
  }
751
664
 
752
665
  #[tokio::test]
753
666
  async fn test_deploy_with_one_instance_no_domain() {
754
667
  // Arrange
755
- let number_of_instances = 1;
756
- let instance_type = InstanceType::T2Micro;
668
+ let instance_type = InstanceType::T3Micro;
757
669
  let domain_name = None;
758
670
 
759
- let spec_graph =
760
- GraphManager::get_spec_graph(number_of_instances, &instance_type, domain_name);
671
+ let spec_graph = GraphManager::get_spec_graph(&instance_type, domain_name);
761
672
 
762
673
  let mut ec2_client_mock = client::Ec2::default();
763
674
  let mut iam_client_mock = client::IAM::default();
@@ -909,7 +820,7 @@ mod tests {
909
820
  );
910
821
 
911
822
  // Act
912
- let (resource_graph, vms, ecr) = graph_manager
823
+ let (resource_graph, vm, ecr) = graph_manager
913
824
  .deploy(&spec_graph)
914
825
  .await
915
826
  .expect("Failed to deploy");
@@ -919,12 +830,12 @@ mod tests {
919
830
  assert_eq!(resource_graph.edge_count(), 14);
920
831
 
921
832
  assert_eq!(
922
- vms,
923
- vec![Vm {
833
+ vm,
834
+ Some(Vm {
924
835
  id: String::from("vm-id-1"),
925
836
  public_ip: String::from("1.2.3.4"),
926
837
  ami: String::from("ami-04dd23e62ed049936"),
927
- instance_type: InstanceType::T2Micro,
838
+ instance_type: InstanceType::T3Micro,
928
839
  user_data: String::from(
929
840
  r#"#!/bin/bash
930
841
  set -e
@@ -942,7 +853,7 @@ mod tests {
942
853
 
943
854
  aws ecr get-login-password --region us-west-2 | podman login --username AWS --password-stdin ecr-uri-1"#
944
855
  )
945
- }]
856
+ })
946
857
  );
947
858
 
948
859
  assert_eq!(
@@ -973,7 +884,7 @@ aws ecr get-login-password --region us-west-2 | podman login --username AWS --pa
973
884
  );
974
885
 
975
886
  // Act
976
- let (resource_graph, vms, ecr) = graph_manager
887
+ let (resource_graph, vm, ecr) = graph_manager
977
888
  .deploy(&spec_graph)
978
889
  .await
979
890
  .expect("Failed to deploy");
@@ -981,7 +892,7 @@ aws ecr get-login-password --region us-west-2 | podman login --username AWS --pa
981
892
  // Assert
982
893
  assert_eq!(resource_graph.node_count(), 0);
983
894
  assert_eq!(resource_graph.edge_count(), 0);
984
- assert!(vms.is_empty());
895
+ assert!(vm.is_none());
985
896
  assert!(ecr.is_none());
986
897
  }
987
898
 
@@ -1036,7 +947,7 @@ aws ecr get-login-password --region us-west-2 | podman login --username AWS --pa
1036
947
  );
1037
948
 
1038
949
  // Act
1039
- let (resource_graph, vms, ecr) = graph_manager
950
+ let (resource_graph, vm, ecr) = graph_manager
1040
951
  .deploy(&spec_graph)
1041
952
  .await
1042
953
  .expect("Failed to deploy");
@@ -1045,7 +956,7 @@ aws ecr get-login-password --region us-west-2 | podman login --username AWS --pa
1045
956
  // 1 root + VPC
1046
957
  assert_eq!(resource_graph.node_count(), 2);
1047
958
  assert_eq!(resource_graph.edge_count(), 1);
1048
- assert!(vms.is_empty());
959
+ assert!(vm.is_none());
1049
960
  assert!(ecr.is_none());
1050
961
 
1051
962
  let vpc_node_exists = resource_graph
@@ -1339,7 +1250,7 @@ aws ecr get-login-password --region us-west-2 | podman login --username AWS --pa
1339
1250
  id: "vm-id-1".to_string(),
1340
1251
  public_ip: "1.2.3.4".to_string(),
1341
1252
  ami: "ami-04dd23e62ed049936".to_string(),
1342
- instance_type: InstanceType::T2Micro,
1253
+ instance_type: InstanceType::T3Micro,
1343
1254
  user_data: String::new(), // Not used in destroy
1344
1255
  })));
1345
1256
 
@@ -2107,7 +2107,7 @@ mod tests {
2107
2107
  let vm = Vm {
2108
2108
  id: String::from("vm-id"),
2109
2109
  public_ip: String::from("1.2.3.4"),
2110
- instance_type: types::InstanceType::T2Micro,
2110
+ instance_type: types::InstanceType::T3Micro,
2111
2111
  ami: String::from("ami-123"),
2112
2112
  user_data: String::new(),
2113
2113
  };
@@ -2148,7 +2148,7 @@ mod tests {
2148
2148
  let vm = Vm {
2149
2149
  id: String::from("vm-id"),
2150
2150
  public_ip: String::from("1.2.3.4"),
2151
- instance_type: types::InstanceType::T2Micro,
2151
+ instance_type: types::InstanceType::T3Micro,
2152
2152
  ami: String::from("ami-123"),
2153
2153
  user_data: String::new(),
2154
2154
  };
@@ -2222,7 +2222,7 @@ mod tests {
2222
2222
  let vm = Vm {
2223
2223
  id: String::from("vm-id"),
2224
2224
  public_ip: String::from("1.2.3.4"),
2225
- instance_type: types::InstanceType::T2Micro,
2225
+ instance_type: types::InstanceType::T3Micro,
2226
2226
  ami: String::from("ami-123"),
2227
2227
  user_data: String::new(),
2228
2228
  };
@@ -2719,7 +2719,7 @@ mod tests {
2719
2719
  };
2720
2720
 
2721
2721
  let vm_spec = VmSpec {
2722
- instance_type: types::InstanceType::T2Micro,
2722
+ instance_type: types::InstanceType::T3Micro,
2723
2723
  ami: String::from("ami-123"),
2724
2724
  user_data: String::from("user-data"),
2725
2725
  };
@@ -2761,7 +2761,7 @@ mod tests {
2761
2761
  Vm {
2762
2762
  id: String::from("vm-id"),
2763
2763
  public_ip: String::from("1.2.3.4"),
2764
- instance_type: types::InstanceType::T2Micro,
2764
+ instance_type: types::InstanceType::T3Micro,
2765
2765
  ami: String::from("ami-123"),
2766
2766
  user_data: String::from(
2767
2767
  "user-data\naws ecr get-login-password --region us-west-2 | podman login --username AWS --password-stdin dkr.ecr.region.amazonaws.com",
@@ -2778,7 +2778,7 @@ mod tests {
2778
2778
  client: &ec2_client_mock,
2779
2779
  };
2780
2780
  let vm_spec = VmSpec {
2781
- instance_type: types::InstanceType::T2Micro,
2781
+ instance_type: types::InstanceType::T3Micro,
2782
2782
  ami: String::from("ami-123"),
2783
2783
  user_data: String::from("user-data"),
2784
2784
  };
@@ -2820,7 +2820,7 @@ mod tests {
2820
2820
  client: &ec2_client_mock,
2821
2821
  };
2822
2822
  let vm_spec = VmSpec {
2823
- instance_type: types::InstanceType::T2Micro,
2823
+ instance_type: types::InstanceType::T3Micro,
2824
2824
  ami: String::from("ami-123"),
2825
2825
  user_data: String::from("user-data"),
2826
2826
  };
@@ -2863,7 +2863,7 @@ mod tests {
2863
2863
  client: &ec2_client_mock,
2864
2864
  };
2865
2865
  let vm_spec = VmSpec {
2866
- instance_type: types::InstanceType::T2Micro,
2866
+ instance_type: types::InstanceType::T3Micro,
2867
2867
  ami: String::from("ami-123"),
2868
2868
  user_data: String::from("user-data"),
2869
2869
  };
@@ -2908,7 +2908,7 @@ mod tests {
2908
2908
  client: &ec2_client_mock,
2909
2909
  };
2910
2910
  let vm_spec = VmSpec {
2911
- instance_type: types::InstanceType::T2Micro,
2911
+ instance_type: types::InstanceType::T3Micro,
2912
2912
  ami: String::from("ami-123"),
2913
2913
  user_data: String::from("user-data"),
2914
2914
  };
@@ -2956,7 +2956,7 @@ mod tests {
2956
2956
  };
2957
2957
 
2958
2958
  let vm_spec = VmSpec {
2959
- instance_type: types::InstanceType::T2Micro,
2959
+ instance_type: types::InstanceType::T3Micro,
2960
2960
  ami: String::from("ami-123"),
2961
2961
  user_data: String::from("user-data"),
2962
2962
  };
@@ -3019,7 +3019,7 @@ mod tests {
3019
3019
  let vm = Vm {
3020
3020
  id: String::from("vm-id"),
3021
3021
  public_ip: String::from("1.2.3.4"),
3022
- instance_type: types::InstanceType::T2Micro,
3022
+ instance_type: types::InstanceType::T3Micro,
3023
3023
  ami: String::from("ami-123"),
3024
3024
  user_data: String::from("user-data"),
3025
3025
  };
@@ -3047,7 +3047,7 @@ mod tests {
3047
3047
  let vm = Vm {
3048
3048
  id: String::from("vm-id"),
3049
3049
  public_ip: String::from("1.2.3.4"),
3050
- instance_type: types::InstanceType::T2Micro,
3050
+ instance_type: types::InstanceType::T3Micro,
3051
3051
  ami: String::from("ami-123"),
3052
3052
  user_data: String::from("user-data"),
3053
3053
  };
@@ -16,7 +16,7 @@ rust-version = { workspace = true }
16
16
  [dependencies]
17
17
  log = { workspace = true }
18
18
  reqwest = { workspace = true }
19
- serde = { workspace = true }
19
+ serde = { workspace = true, features = ["derive"] }
20
20
  serde_json = { workspace = true }
21
21
  tokio = { workspace = true }
22
22
 
@@ -230,3 +230,7 @@ Total: $92 per month
230
230
  - 1 EC2 [t4g.medium](https://aws.amazon.com/ec2/pricing/on-demand/) instance ($0.0336 per hour): $25.5 per month
231
231
 
232
232
  Total: $25.5 per month
233
+
234
+ ## Repo stats
235
+
236
+ ![Alt](https://repobeats.axiom.co/api/embed/7127395110cea0828bf52367026a5768d9c016e8.svg "Repobeats analytics image")
@@ -230,3 +230,7 @@ Total: $92 per month
230
230
  - 1 EC2 [t4g.medium](https://aws.amazon.com/ec2/pricing/on-demand/) instance ($0.0336 per hour): $25.5 per month
231
231
 
232
232
  Total: $25.5 per month
233
+
234
+ ## Repo stats
235
+
236
+ ![Alt](https://repobeats.axiom.co/api/embed/7127395110cea0828bf52367026a5768d9c016e8.svg "Repobeats analytics image")
@@ -16,8 +16,6 @@ mod user_state;
16
16
  pub struct OrchestratorWithGraph;
17
17
 
18
18
  impl OrchestratorWithGraph {
19
- const INSTANCE_TYPE: InstanceType = InstanceType::T2Micro;
20
-
21
19
  pub async fn deploy(&self) -> Result<(), Box<dyn std::error::Error>> {
22
20
  let mut config = config::Config::new(None)?;
23
21
 
@@ -33,34 +31,26 @@ impl OrchestratorWithGraph {
33
31
  backend::get_state_backend::<user_state::UserState>(&config.project.user_state_backend);
34
32
  let (mut user_state, _loaded) = user_state_backend.load().await?;
35
33
 
36
- let number_of_instances =
37
- get_number_of_needed_instances(&services_graph, &Self::INSTANCE_TYPE)?;
34
+ let instance_type = get_instance_type(&services_graph)?;
38
35
 
39
- log::info!("Instances to be created: {number_of_instances}");
36
+ log::info!("Instance to be created: {instance_type:?}");
40
37
 
41
38
  let spec_graph = infra::graph::GraphManager::get_spec_graph(
42
- number_of_instances,
43
- &Self::INSTANCE_TYPE,
39
+ &instance_type,
44
40
  config.project.domain.clone(),
45
41
  );
46
42
 
47
43
  let infra_graph_manager = infra::graph::GraphManager::new().await;
48
- let (resource_graph, vms, ecr) = infra_graph_manager.deploy(&spec_graph).await?;
44
+ let (resource_graph, vm, ecr) = infra_graph_manager.deploy(&spec_graph).await?;
49
45
 
50
46
  let state = infra::state::State::from_graph(&resource_graph);
51
47
  let () = infra_state_backend.save(&state).await?;
52
48
 
53
- for vm in &vms {
54
- // Add missing instances to state
55
- // TODO: Handle removing instances
56
- if user_state.instances.contains_key(&vm.public_ip) {
57
- continue;
58
- }
59
-
49
+ if let Some(vm) = vm {
60
50
  let instance_info = vm.instance_type.get_info();
61
51
 
62
52
  user_state.instances.insert(
63
- vm.public_ip.clone(),
53
+ vm.public_ip,
64
54
  user_state::Instance {
65
55
  cpus: instance_info.cpus,
66
56
  memory: instance_info.memory,
@@ -141,13 +131,10 @@ impl OrchestratorWithGraph {
141
131
  }
142
132
  }
143
133
 
144
- /// Calculates the number of instances needed to run the services
145
- /// For now we expect that an individual service required resources will not exceed
146
- /// a single EC2 instance capacity
147
- fn get_number_of_needed_instances(
134
+ /// Tries to find an instance type which can fit all user-requested services
135
+ fn get_instance_type(
148
136
  services_graph: &Graph<config::Node, String>,
149
- instance_type: &InstanceType,
150
- ) -> Result<u32, Box<dyn std::error::Error>> {
137
+ ) -> Result<InstanceType, Box<dyn std::error::Error>> {
151
138
  let sorted_graph = infra::graph::kahn_traverse(services_graph)?;
152
139
 
153
140
  let total_services_cpus = sorted_graph
@@ -174,15 +161,12 @@ fn get_number_of_needed_instances(
174
161
  .map(|service| service.memory)
175
162
  .sum::<u64>();
176
163
 
177
- let instance_info = instance_type.get_info();
164
+ let instance_type = InstanceType::from_resources(total_services_cpus, total_services_memory);
178
165
 
179
- let needed_instances_count_by_cpus = total_services_cpus.div_ceil(instance_info.cpus);
180
- let needed_instances_count_by_memory = total_services_memory.div_ceil(instance_info.memory);
181
-
182
- Ok(std::cmp::max(
183
- needed_instances_count_by_cpus,
184
- u32::try_from(needed_instances_count_by_memory).unwrap_or_default(),
185
- ))
166
+ match instance_type {
167
+ Some(instance_type) => Ok(instance_type),
168
+ None => Err("Failed to get instance type to fit all services".into()),
169
+ }
186
170
  }
187
171
 
188
172
  /// Deploys user services
@@ -28,7 +28,7 @@ wheels = [
28
28
 
29
29
  [[package]]
30
30
  name = "opencloudtool"
31
- version = "0.6.0"
31
+ version = "0.7.0"
32
32
  source = { editable = "." }
33
33
 
34
34
  [package.dev-dependencies]
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "opencloudtool"
7
- version = "0.6.0"
7
+ version = "0.7.0"
8
8
  readme = "README.md"
9
9
  requires-python = ">=3.8"
10
10
  dependencies = []
File without changes