feat: Inventory PhysicalHost persistence with sqlx and local sqlite db #125
| @ -0,0 +1,32 @@ | |||||||
|  | { | ||||||
|  |   "db_name": "SQLite", | ||||||
|  |   "query": "SELECT id, version_id, data as \"data: Json<PhysicalHost>\" FROM physical_hosts WHERE id = ? ORDER BY version_id DESC LIMIT 1", | ||||||
|  |   "describe": { | ||||||
|  |     "columns": [ | ||||||
|  |       { | ||||||
|  |         "name": "id", | ||||||
|  |         "ordinal": 0, | ||||||
|  |         "type_info": "Text" | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         "name": "version_id", | ||||||
|  |         "ordinal": 1, | ||||||
|  |         "type_info": "Text" | ||||||
|  |       }, | ||||||
|  |       { | ||||||
|  |         "name": "data: Json<PhysicalHost>", | ||||||
|  |         "ordinal": 2, | ||||||
|  |         "type_info": "Null" | ||||||
|  |       } | ||||||
|  |     ], | ||||||
|  |     "parameters": { | ||||||
|  |       "Right": 1 | ||||||
|  |     }, | ||||||
|  |     "nullable": [ | ||||||
|  |       false, | ||||||
|  |       false, | ||||||
|  |       false | ||||||
|  |     ] | ||||||
|  |   }, | ||||||
|  |   "hash": "934035c7ca6e064815393e4e049a7934b0a7fac04a4fe4b2a354f0443d630990" | ||||||
|  | } | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | { | ||||||
|  |   "db_name": "SQLite", | ||||||
|  |   "query": "INSERT INTO physical_hosts (id, version_id, data) VALUES (?, ?, ?)", | ||||||
|  |   "describe": { | ||||||
|  |     "columns": [], | ||||||
|  |     "parameters": { | ||||||
|  |       "Right": 3 | ||||||
|  |     }, | ||||||
|  |     "nullable": [] | ||||||
|  |   }, | ||||||
|  |   "hash": "f10f615ee42129ffa293e46f2f893d65a237d31d24b74a29c6a8d8420d255ab8" | ||||||
|  | } | ||||||
							
								
								
									
										343
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										343
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							| @ -474,6 +474,15 @@ dependencies = [ | |||||||
|  "syn 2.0.105", |  "syn 2.0.105", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "atoi" | ||||||
|  | version = "2.0.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" | ||||||
|  | dependencies = [ | ||||||
|  |  "num-traits", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "atomic-waker" | name = "atomic-waker" | ||||||
| version = "1.1.2" | version = "1.1.2" | ||||||
| @ -1052,6 +1061,21 @@ dependencies = [ | |||||||
|  "libc", |  "libc", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "crc" | ||||||
|  | version = "3.3.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" | ||||||
|  | dependencies = [ | ||||||
|  |  "crc-catalog", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "crc-catalog" | ||||||
|  | version = "2.4.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "crc32fast" | name = "crc32fast" | ||||||
| version = "1.4.2" | version = "1.4.2" | ||||||
| @ -1089,6 +1113,15 @@ dependencies = [ | |||||||
|  "crossbeam-utils", |  "crossbeam-utils", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "crossbeam-queue" | ||||||
|  | version = "0.3.12" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" | ||||||
|  | dependencies = [ | ||||||
|  |  "crossbeam-utils", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "crossbeam-utils" | name = "crossbeam-utils" | ||||||
| version = "0.8.21" | version = "0.8.21" | ||||||
| @ -1409,6 +1442,12 @@ dependencies = [ | |||||||
|  "syn 2.0.105", |  "syn 2.0.105", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "dotenvy" | ||||||
|  | version = "0.15.7" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "dyn-clone" | name = "dyn-clone" | ||||||
| version = "1.0.19" | version = "1.0.19" | ||||||
| @ -1471,6 +1510,9 @@ name = "either" | |||||||
| version = "1.15.0" | version = "1.15.0" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" | ||||||
|  | dependencies = [ | ||||||
|  |  "serde", | ||||||
|  | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "elliptic-curve" | name = "elliptic-curve" | ||||||
| @ -1586,6 +1628,17 @@ dependencies = [ | |||||||
|  "windows-sys 0.60.2", |  "windows-sys 0.60.2", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "etcetera" | ||||||
|  | version = "0.8.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" | ||||||
|  | dependencies = [ | ||||||
|  |  "cfg-if", | ||||||
|  |  "home", | ||||||
|  |  "windows-sys 0.48.0", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "event-listener" | name = "event-listener" | ||||||
| version = "5.4.0" | version = "5.4.0" | ||||||
| @ -1984,6 +2037,17 @@ dependencies = [ | |||||||
|  "futures-util", |  "futures-util", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "futures-intrusive" | ||||||
|  | version = "0.5.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" | ||||||
|  | dependencies = [ | ||||||
|  |  "futures-core", | ||||||
|  |  "lock_api", | ||||||
|  |  "parking_lot", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "futures-io" | name = "futures-io" | ||||||
| version = "0.3.31" | version = "0.3.31" | ||||||
| @ -2241,11 +2305,13 @@ dependencies = [ | |||||||
|  "serde_with", |  "serde_with", | ||||||
|  "serde_yaml", |  "serde_yaml", | ||||||
|  "similar", |  "similar", | ||||||
|  |  "sqlx", | ||||||
|  "strum 0.27.1", |  "strum 0.27.1", | ||||||
|  "tar", |  "tar", | ||||||
|  "temp-dir", |  "temp-dir", | ||||||
|  "temp-file", |  "temp-file", | ||||||
|  "tempfile", |  "tempfile", | ||||||
|  |  "thiserror 2.0.14", | ||||||
|  "tokio", |  "tokio", | ||||||
|  "tokio-util", |  "tokio-util", | ||||||
|  "url", |  "url", | ||||||
| @ -2391,6 +2457,15 @@ dependencies = [ | |||||||
|  "foldhash", |  "foldhash", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "hashlink" | ||||||
|  | version = "0.10.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" | ||||||
|  | dependencies = [ | ||||||
|  |  "hashbrown 0.15.4", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "headers" | name = "headers" | ||||||
| version = "0.4.1" | version = "0.4.1" | ||||||
| @ -2960,7 +3035,7 @@ checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" | |||||||
| [[package]] | [[package]] | ||||||
| name = "infisical" | name = "infisical" | ||||||
| version = "0.0.2" | version = "0.0.2" | ||||||
| source = "git+https://github.com/jggc/rust-sdk.git?branch=patch-1#5a8509ef5483a5798c5d1a7f7ebeb5ba5b783253" | source = "git+https://github.com/jggc/rust-sdk.git?branch=patch-1#30d820194d29491411bd14f6c2e18ec500bb0b14" | ||||||
| dependencies = [ | dependencies = [ | ||||||
|  "base64 0.22.1", |  "base64 0.22.1", | ||||||
|  "reqwest 0.12.20", |  "reqwest 0.12.20", | ||||||
| @ -3333,6 +3408,17 @@ dependencies = [ | |||||||
|  "redox_syscall", |  "redox_syscall", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "libsqlite3-sys" | ||||||
|  | version = "0.30.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" | ||||||
|  | dependencies = [ | ||||||
|  |  "cc", | ||||||
|  |  "pkg-config", | ||||||
|  |  "vcpkg", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "linux-raw-sys" | name = "linux-raw-sys" | ||||||
| version = "0.4.15" | version = "0.4.15" | ||||||
| @ -3429,6 +3515,16 @@ version = "0.1.2" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" | checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "md-5" | ||||||
|  | version = "0.10.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" | ||||||
|  | dependencies = [ | ||||||
|  |  "cfg-if", | ||||||
|  |  "digest", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "md5" | name = "md5" | ||||||
| version = "0.7.0" | version = "0.7.0" | ||||||
| @ -5280,6 +5376,9 @@ name = "smallvec" | |||||||
| version = "1.15.1" | version = "1.15.1" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" | ||||||
|  | dependencies = [ | ||||||
|  |  "serde", | ||||||
|  | ] | ||||||
| 
 | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "snafu" | name = "snafu" | ||||||
| @ -5352,6 +5451,194 @@ dependencies = [ | |||||||
|  "der", |  "der", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sqlx" | ||||||
|  | version = "0.8.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" | ||||||
|  | dependencies = [ | ||||||
|  |  "sqlx-core", | ||||||
|  |  "sqlx-macros", | ||||||
|  |  "sqlx-mysql", | ||||||
|  |  "sqlx-postgres", | ||||||
|  |  "sqlx-sqlite", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sqlx-core" | ||||||
|  | version = "0.8.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" | ||||||
|  | dependencies = [ | ||||||
|  |  "base64 0.22.1", | ||||||
|  |  "bytes", | ||||||
|  |  "crc", | ||||||
|  |  "crossbeam-queue", | ||||||
|  |  "either", | ||||||
|  |  "event-listener", | ||||||
|  |  "futures-core", | ||||||
|  |  "futures-intrusive", | ||||||
|  |  "futures-io", | ||||||
|  |  "futures-util", | ||||||
|  |  "hashbrown 0.15.4", | ||||||
|  |  "hashlink", | ||||||
|  |  "indexmap 2.10.0", | ||||||
|  |  "log", | ||||||
|  |  "memchr", | ||||||
|  |  "once_cell", | ||||||
|  |  "percent-encoding", | ||||||
|  |  "serde", | ||||||
|  |  "serde_json", | ||||||
|  |  "sha2", | ||||||
|  |  "smallvec", | ||||||
|  |  "thiserror 2.0.14", | ||||||
|  |  "tokio", | ||||||
|  |  "tokio-stream", | ||||||
|  |  "tracing", | ||||||
|  |  "url", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sqlx-macros" | ||||||
|  | version = "0.8.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" | ||||||
|  | dependencies = [ | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "sqlx-core", | ||||||
|  |  "sqlx-macros-core", | ||||||
|  |  "syn 2.0.105", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sqlx-macros-core" | ||||||
|  | version = "0.8.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" | ||||||
|  | dependencies = [ | ||||||
|  |  "dotenvy", | ||||||
|  |  "either", | ||||||
|  |  "heck", | ||||||
|  |  "hex", | ||||||
|  |  "once_cell", | ||||||
|  |  "proc-macro2", | ||||||
|  |  "quote", | ||||||
|  |  "serde", | ||||||
|  |  "serde_json", | ||||||
|  |  "sha2", | ||||||
|  |  "sqlx-core", | ||||||
|  |  "sqlx-mysql", | ||||||
|  |  "sqlx-postgres", | ||||||
|  |  "sqlx-sqlite", | ||||||
|  |  "syn 2.0.105", | ||||||
|  |  "tokio", | ||||||
|  |  "url", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sqlx-mysql" | ||||||
|  | version = "0.8.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" | ||||||
|  | dependencies = [ | ||||||
|  |  "atoi", | ||||||
|  |  "base64 0.22.1", | ||||||
|  |  "bitflags 2.9.1", | ||||||
|  |  "byteorder", | ||||||
|  |  "bytes", | ||||||
|  |  "crc", | ||||||
|  |  "digest", | ||||||
|  |  "dotenvy", | ||||||
|  |  "either", | ||||||
|  |  "futures-channel", | ||||||
|  |  "futures-core", | ||||||
|  |  "futures-io", | ||||||
|  |  "futures-util", | ||||||
|  |  "generic-array", | ||||||
|  |  "hex", | ||||||
|  |  "hkdf", | ||||||
|  |  "hmac", | ||||||
|  |  "itoa", | ||||||
|  |  "log", | ||||||
|  |  "md-5", | ||||||
|  |  "memchr", | ||||||
|  |  "once_cell", | ||||||
|  |  "percent-encoding", | ||||||
|  |  "rand 0.8.5", | ||||||
|  |  "rsa", | ||||||
|  |  "serde", | ||||||
|  |  "sha1", | ||||||
|  |  "sha2", | ||||||
|  |  "smallvec", | ||||||
|  |  "sqlx-core", | ||||||
|  |  "stringprep", | ||||||
|  |  "thiserror 2.0.14", | ||||||
|  |  "tracing", | ||||||
|  |  "whoami", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sqlx-postgres" | ||||||
|  | version = "0.8.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" | ||||||
|  | dependencies = [ | ||||||
|  |  "atoi", | ||||||
|  |  "base64 0.22.1", | ||||||
|  |  "bitflags 2.9.1", | ||||||
|  |  "byteorder", | ||||||
|  |  "crc", | ||||||
|  |  "dotenvy", | ||||||
|  |  "etcetera", | ||||||
|  |  "futures-channel", | ||||||
|  |  "futures-core", | ||||||
|  |  "futures-util", | ||||||
|  |  "hex", | ||||||
|  |  "hkdf", | ||||||
|  |  "hmac", | ||||||
|  |  "home", | ||||||
|  |  "itoa", | ||||||
|  |  "log", | ||||||
|  |  "md-5", | ||||||
|  |  "memchr", | ||||||
|  |  "once_cell", | ||||||
|  |  "rand 0.8.5", | ||||||
|  |  "serde", | ||||||
|  |  "serde_json", | ||||||
|  |  "sha2", | ||||||
|  |  "smallvec", | ||||||
|  |  "sqlx-core", | ||||||
|  |  "stringprep", | ||||||
|  |  "thiserror 2.0.14", | ||||||
|  |  "tracing", | ||||||
|  |  "whoami", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "sqlx-sqlite" | ||||||
|  | version = "0.8.6" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" | ||||||
|  | dependencies = [ | ||||||
|  |  "atoi", | ||||||
|  |  "flume", | ||||||
|  |  "futures-channel", | ||||||
|  |  "futures-core", | ||||||
|  |  "futures-executor", | ||||||
|  |  "futures-intrusive", | ||||||
|  |  "futures-util", | ||||||
|  |  "libsqlite3-sys", | ||||||
|  |  "log", | ||||||
|  |  "percent-encoding", | ||||||
|  |  "serde", | ||||||
|  |  "serde_urlencoded", | ||||||
|  |  "sqlx-core", | ||||||
|  |  "thiserror 2.0.14", | ||||||
|  |  "tracing", | ||||||
|  |  "url", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "ssh-cipher" | name = "ssh-cipher" | ||||||
| version = "0.2.0" | version = "0.2.0" | ||||||
| @ -5415,6 +5702,17 @@ version = "1.1.0" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "stringprep" | ||||||
|  | version = "0.1.5" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" | ||||||
|  | dependencies = [ | ||||||
|  |  "unicode-bidi", | ||||||
|  |  "unicode-normalization", | ||||||
|  |  "unicode-properties", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "strsim" | name = "strsim" | ||||||
| version = "0.11.1" | version = "0.11.1" | ||||||
| @ -6018,12 +6316,33 @@ version = "0.1.7" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" | checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "unicode-bidi" | ||||||
|  | version = "0.3.18" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "unicode-ident" | name = "unicode-ident" | ||||||
| version = "1.0.18" | version = "1.0.18" | ||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "unicode-normalization" | ||||||
|  | version = "0.1.24" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" | ||||||
|  | dependencies = [ | ||||||
|  |  "tinyvec", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "unicode-properties" | ||||||
|  | version = "0.1.3" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "unicode-segmentation" | name = "unicode-segmentation" | ||||||
| version = "1.12.0" | version = "1.12.0" | ||||||
| @ -6147,6 +6466,12 @@ version = "0.1.1" | |||||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
| checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "vcpkg" | ||||||
|  | version = "0.2.15" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "version_check" | name = "version_check" | ||||||
| version = "0.9.5" | version = "0.9.5" | ||||||
| @ -6186,6 +6511,12 @@ dependencies = [ | |||||||
|  "wit-bindgen-rt", |  "wit-bindgen-rt", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "wasite" | ||||||
|  | version = "0.1.0" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "wasm-bindgen" | name = "wasm-bindgen" | ||||||
| version = "0.2.100" | version = "0.2.100" | ||||||
| @ -6306,6 +6637,16 @@ dependencies = [ | |||||||
|  "rustls-pki-types", |  "rustls-pki-types", | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | [[package]] | ||||||
|  | name = "whoami" | ||||||
|  | version = "1.6.1" | ||||||
|  | source = "registry+https://github.com/rust-lang/crates.io-index" | ||||||
|  | checksum = "5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" | ||||||
|  | dependencies = [ | ||||||
|  |  "libredox", | ||||||
|  |  "wasite", | ||||||
|  | ] | ||||||
|  | 
 | ||||||
| [[package]] | [[package]] | ||||||
| name = "winapi" | name = "winapi" | ||||||
| version = "0.2.8" | version = "0.2.8" | ||||||
|  | |||||||
| @ -65,3 +65,5 @@ directories = "6.0.0" | |||||||
| thiserror = "2.0.14" | thiserror = "2.0.14" | ||||||
| serde = { version = "1.0.209", features = ["derive", "rc"] } | serde = { version = "1.0.209", features = ["derive", "rc"] } | ||||||
| serde_json = "1.0.127" | serde_json = "1.0.127" | ||||||
|  | askama = "0.14" | ||||||
|  | sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite" ] } | ||||||
|  | |||||||
| @ -65,10 +65,12 @@ kube-derive = "1.1.0" | |||||||
| bollard.workspace = true | bollard.workspace = true | ||||||
| tar.workspace = true | tar.workspace = true | ||||||
| base64.workspace = true | base64.workspace = true | ||||||
|  | thiserror.workspace = true | ||||||
| once_cell = "1.21.3" | once_cell = "1.21.3" | ||||||
| harmony_inventory_agent = { path = "../harmony_inventory_agent" } | harmony_inventory_agent = { path = "../harmony_inventory_agent" } | ||||||
| harmony_secret_derive = { version = "0.1.0", path = "../harmony_secret_derive" } | harmony_secret_derive = { version = "0.1.0", path = "../harmony_secret_derive" } | ||||||
| askama = "0.14.0" | askama.workspace = true | ||||||
|  | sqlx.workspace = true | ||||||
| 
 | 
 | ||||||
| [dev-dependencies] | [dev-dependencies] | ||||||
| pretty_assertions.workspace = true | pretty_assertions.workspace = true | ||||||
|  | |||||||
| @ -24,6 +24,14 @@ pub struct Id { | |||||||
|     value: String, |     value: String, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl Id { | ||||||
|  |     pub fn empty() -> Self { | ||||||
|  |         Id { | ||||||
|  |             value: String::new(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl FromStr for Id { | impl FromStr for Id { | ||||||
|     type Err = (); |     type Err = (); | ||||||
| 
 | 
 | ||||||
| @ -34,6 +42,12 @@ impl FromStr for Id { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl From<String> for Id { | ||||||
|  |     fn from(value: String) -> Self { | ||||||
|  |         Self { value } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl std::fmt::Display for Id { | impl std::fmt::Display for Id { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|         f.write_str(&self.value) |         f.write_str(&self.value) | ||||||
|  | |||||||
| @ -1,8 +1,8 @@ | |||||||
| use std::sync::Arc; | use std::{str::FromStr, sync::Arc}; | ||||||
| 
 | 
 | ||||||
| use derive_new::new; | use derive_new::new; | ||||||
| use harmony_types::net::MacAddress; | use harmony_types::net::MacAddress; | ||||||
| use serde::{Serialize, Serializer, ser::SerializeStruct}; | use serde::{Deserialize, Serialize, Serializer, ser::SerializeStruct}; | ||||||
| use serde_value::Value; | use serde_value::Value; | ||||||
| 
 | 
 | ||||||
| pub type HostGroup = Vec<PhysicalHost>; | pub type HostGroup = Vec<PhysicalHost>; | ||||||
| @ -11,6 +11,7 @@ pub type FirewallGroup = Vec<PhysicalHost>; | |||||||
| 
 | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| pub struct PhysicalHost { | pub struct PhysicalHost { | ||||||
|  |     pub id: Id, | ||||||
|     pub category: HostCategory, |     pub category: HostCategory, | ||||||
|     pub network: Vec<NetworkInterface>, |     pub network: Vec<NetworkInterface>, | ||||||
|     pub management: Arc<dyn ManagementInterface>, |     pub management: Arc<dyn ManagementInterface>, | ||||||
| @ -23,6 +24,7 @@ pub struct PhysicalHost { | |||||||
| impl PhysicalHost { | impl PhysicalHost { | ||||||
|     pub fn empty(category: HostCategory) -> Self { |     pub fn empty(category: HostCategory) -> Self { | ||||||
|         Self { |         Self { | ||||||
|  |             id: Id::empty(), | ||||||
|             category, |             category, | ||||||
|             network: vec![], |             network: vec![], | ||||||
|             storage: vec![], |             storage: vec![], | ||||||
| @ -128,6 +130,15 @@ impl Serialize for PhysicalHost { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl<'de> Deserialize<'de> for PhysicalHost { | ||||||
|  |     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> | ||||||
|  |     where | ||||||
|  |         D: serde::Deserializer<'de>, | ||||||
|  |     { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(new, Serialize)] | #[derive(new, Serialize)] | ||||||
| pub struct ManualManagementInterface; | pub struct ManualManagementInterface; | ||||||
| 
 | 
 | ||||||
| @ -187,6 +198,8 @@ pub struct NetworkInterface { | |||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| use harmony_macros::mac_address; | use harmony_macros::mac_address; | ||||||
|  | 
 | ||||||
|  | use crate::data::Id; | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| impl NetworkInterface { | impl NetworkInterface { | ||||||
|     pub fn dummy() -> Self { |     pub fn dummy() -> Self { | ||||||
| @ -304,6 +317,7 @@ mod tests { | |||||||
|     fn test_serialize_physical_host_with_hp_ilo() { |     fn test_serialize_physical_host_with_hp_ilo() { | ||||||
|         // Create a PhysicalHost with HP iLO management
 |         // Create a PhysicalHost with HP iLO management
 | ||||||
|         let host = PhysicalHost { |         let host = PhysicalHost { | ||||||
|  |             id: Id::empty(), | ||||||
|             category: HostCategory::Server, |             category: HostCategory::Server, | ||||||
|             network: vec![NetworkInterface::dummy()], |             network: vec![NetworkInterface::dummy()], | ||||||
|             management: Arc::new(MockHPIlo { |             management: Arc::new(MockHPIlo { | ||||||
| @ -341,6 +355,7 @@ mod tests { | |||||||
|     fn test_serialize_physical_host_with_dell_idrac() { |     fn test_serialize_physical_host_with_dell_idrac() { | ||||||
|         // Create a PhysicalHost with Dell iDRAC management
 |         // Create a PhysicalHost with Dell iDRAC management
 | ||||||
|         let host = PhysicalHost { |         let host = PhysicalHost { | ||||||
|  |             id: Id::empty(), | ||||||
|             category: HostCategory::Server, |             category: HostCategory::Server, | ||||||
|             network: vec![NetworkInterface::dummy()], |             network: vec![NetworkInterface::dummy()], | ||||||
|             management: Arc::new(MockDellIdrac { |             management: Arc::new(MockDellIdrac { | ||||||
| @ -375,6 +390,7 @@ mod tests { | |||||||
|     fn test_different_management_implementations_produce_valid_json() { |     fn test_different_management_implementations_produce_valid_json() { | ||||||
|         // Create hosts with different management implementations
 |         // Create hosts with different management implementations
 | ||||||
|         let host1 = PhysicalHost { |         let host1 = PhysicalHost { | ||||||
|  |             id: Id::empty(), | ||||||
|             category: HostCategory::Server, |             category: HostCategory::Server, | ||||||
|             network: vec![], |             network: vec![], | ||||||
|             management: Arc::new(MockHPIlo { |             management: Arc::new(MockHPIlo { | ||||||
| @ -390,6 +406,7 @@ mod tests { | |||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         let host2 = PhysicalHost { |         let host2 = PhysicalHost { | ||||||
|  |             id: Id::empty(), | ||||||
|             category: HostCategory::Server, |             category: HostCategory::Server, | ||||||
|             network: vec![], |             network: vec![], | ||||||
|             management: Arc::new(MockDellIdrac { |             management: Arc::new(MockDellIdrac { | ||||||
|  | |||||||
| @ -1,3 +1,6 @@ | |||||||
|  | mod repository; | ||||||
|  | pub use repository::*; | ||||||
|  | 
 | ||||||
| #[derive(Debug, new, Clone)] | #[derive(Debug, new, Clone)] | ||||||
| pub struct InventoryFilter { | pub struct InventoryFilter { | ||||||
|     target: Vec<Filter>, |     target: Vec<Filter>, | ||||||
|  | |||||||
							
								
								
									
										25
									
								
								harmony/src/domain/inventory/repository.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								harmony/src/domain/inventory/repository.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | use async_trait::async_trait; | ||||||
|  | 
 | ||||||
|  | use crate::hardware::PhysicalHost; | ||||||
|  | 
 | ||||||
|  | /// Errors that can occur within the repository layer.
 | ||||||
|  | #[derive(thiserror::Error, Debug)] | ||||||
|  | pub enum RepoError { | ||||||
|  |     #[error("Database query failed: {0}")] | ||||||
|  |     QueryFailed(String), | ||||||
|  |     #[error("Data serialization failed: {0}")] | ||||||
|  |     Serialization(String), | ||||||
|  |     #[error("Data deserialization failed: {0}")] | ||||||
|  |     Deserialization(String), | ||||||
|  |     #[error("Could not connect to the database: {0}")] | ||||||
|  |     ConnectionFailed(String), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // --- Trait and Implementation ---
 | ||||||
|  | 
 | ||||||
|  | /// Defines the contract for inventory persistence.
 | ||||||
|  | #[async_trait] | ||||||
|  | pub trait InventoryRepository: Send + Sync + 'static { | ||||||
|  |     async fn save(&self, host: &PhysicalHost) -> Result<(), RepoError>; | ||||||
|  |     async fn get_latest_by_id(&self, host_id: &str) -> Result<Option<PhysicalHost>, RepoError>; | ||||||
|  | |||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								harmony/src/infra/inventory/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								harmony/src/infra/inventory/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | mod sqlite; | ||||||
							
								
								
									
										69
									
								
								harmony/src/infra/inventory/sqlite.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								harmony/src/infra/inventory/sqlite.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | |||||||
|  | use crate::{ | ||||||
|  |     data::Id, | ||||||
|  |     hardware::PhysicalHost, | ||||||
|  |     inventory::{InventoryRepository, RepoError}, | ||||||
|  | }; | ||||||
|  | use async_trait::async_trait; | ||||||
|  | use log::{info, warn}; | ||||||
|  | use sqlx::{Pool, Sqlite, SqlitePool}; | ||||||
|  | 
 | ||||||
|  | /// A thread-safe, connection-pooled repository using SQLite.
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct SqliteInventoryRepository { | ||||||
|  |     pool: Pool<Sqlite>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl SqliteInventoryRepository { | ||||||
|  |     pub async fn new(database_url: &str) -> Result<Self, RepoError> { | ||||||
|  |         let pool = SqlitePool::connect(database_url) | ||||||
|  |             .await | ||||||
|  |             .map_err(|e| RepoError::ConnectionFailed(e.to_string()))?; | ||||||
|  | 
 | ||||||
|  |         todo!("make sure migrations are up to date"); | ||||||
|  |         info!( | ||||||
|  |             "SQLite inventory repository initialized at '{}'", | ||||||
|  |             database_url, | ||||||
|  |         ); | ||||||
|  |         Ok(Self { pool }) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[async_trait] | ||||||
|  | impl InventoryRepository for SqliteInventoryRepository { | ||||||
|  |     async fn save(&self, host: &PhysicalHost) -> Result<(), RepoError> { | ||||||
|  |         let data = serde_json::to_vec(host).map_err(|e| RepoError::Serialization(e.to_string()))?; | ||||||
| 
				
					
						letian
						commented  Could this struct evolve in time and that at some point we update an existing physical host instead of just saving a new one every time? Could this struct evolve in time and that at some point we update an existing physical host instead of just saving a new one every time? | |||||||
|  | 
 | ||||||
|  |         let id = Id::default().to_string(); | ||||||
|  |         let host_id = host.id.to_string(); | ||||||
|  | 
 | ||||||
|  |         sqlx::query!( | ||||||
|  |             "INSERT INTO physical_hosts (id, version_id, data) VALUES (?, ?, ?)", | ||||||
|  |             host_id, | ||||||
|  |             id, | ||||||
|  |             data, | ||||||
|  |         ) | ||||||
|  |         .execute(&self.pool) | ||||||
|  |         .await?; | ||||||
|  | 
 | ||||||
|  |         info!("Saved new inventory version for host '{}'", host.id); | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     async fn get_latest_by_id(&self, host_id: &str) -> Result<Option<PhysicalHost>, RepoError> { | ||||||
|  |         let row = sqlx::query_as!( | ||||||
|  |             DbHost, | ||||||
|  |             r#"SELECT id, version_id, data as "data: Json<PhysicalHost>" FROM physical_hosts WHERE id = ? ORDER BY version_id DESC LIMIT 1"#, | ||||||
|  |             host_id | ||||||
|  |         ) | ||||||
|  |         .fetch_optional(&self.pool) | ||||||
|  |         .await?; | ||||||
|  |         todo!() | ||||||
| 
					
					letian marked this conversation as resolved
					
				 
				
					
						letian
						commented  Do we still need this? Do we still need this? | |||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | use sqlx::types::Json; | ||||||
|  | struct DbHost { | ||||||
|  |     data: Json<PhysicalHost>, | ||||||
|  |     id: Id, | ||||||
|  |     version_id: Id, | ||||||
|  | } | ||||||
| @ -1,4 +1,6 @@ | |||||||
| pub mod executors; | pub mod executors; | ||||||
| pub mod hp_ilo; | pub mod hp_ilo; | ||||||
| pub mod intel_amt; | pub mod intel_amt; | ||||||
|  | pub mod inventory; | ||||||
| pub mod opnsense; | pub mod opnsense; | ||||||
|  | mod sqlx; | ||||||
|  | |||||||
							
								
								
									
										36
									
								
								harmony/src/infra/sqlx.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								harmony/src/infra/sqlx.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,36 @@ | |||||||
|  | use crate::inventory::RepoError; | ||||||
|  | 
 | ||||||
|  | impl From<sqlx::Error> for RepoError { | ||||||
|  |     fn from(value: sqlx::Error) -> Self { | ||||||
|  |         match value { | ||||||
|  |             sqlx::Error::Configuration(_) | ||||||
|  |             | sqlx::Error::Io(_) | ||||||
|  |             | sqlx::Error::Tls(_) | ||||||
|  |             | sqlx::Error::Protocol(_) | ||||||
|  |             | sqlx::Error::PoolTimedOut | ||||||
|  |             | sqlx::Error::PoolClosed | ||||||
|  |             | sqlx::Error::WorkerCrashed => RepoError::ConnectionFailed(value.to_string()), | ||||||
|  |             sqlx::Error::InvalidArgument(_) | ||||||
|  |             | sqlx::Error::Database(_) | ||||||
|  |             | sqlx::Error::RowNotFound | ||||||
|  |             | sqlx::Error::TypeNotFound { .. } | ||||||
|  |             | sqlx::Error::ColumnIndexOutOfBounds { .. } | ||||||
|  |             | sqlx::Error::ColumnNotFound(_) | ||||||
|  |             | sqlx::Error::AnyDriverError(_) | ||||||
|  |             | sqlx::Error::Migrate(_) | ||||||
|  |             | sqlx::Error::InvalidSavePointStatement | ||||||
|  |             | sqlx::Error::BeginFailed => RepoError::QueryFailed(value.to_string()), | ||||||
|  |             sqlx::Error::Encode(_) => RepoError::Serialization(value.to_string()), | ||||||
|  |             sqlx::Error::Decode(_) | sqlx::Error::ColumnDecode { .. } => { | ||||||
|  |                 RepoError::Deserialization(value.to_string()) | ||||||
|  |             } | ||||||
|  |             _ => RepoError::QueryFailed(value.to_string()), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl From<serde_json::Error> for RepoError { | ||||||
|  |     fn from(value: serde_json::Error) -> Self { | ||||||
|  |         RepoError::Serialization(value.to_string()) | ||||||
|  |     } | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	
should we use the
Idtype instead of a str here?