diff --git a/Cargo.lock b/Cargo.lock index a98c525..4d2240a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1038,6 +1038,7 @@ dependencies = [ "futures", "futures-core", "pretty_assertions", + "regex", "reqwest", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index a924316..f5d0e3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,4 @@ serial_test = "3.1" tower = { version = "0.5", features = ["timeout", "limit", "retry", "buffer"] } tower-resilience = { version = "0.3.8", features = ["retry"] } futures = "0.3" +regex = "1.11" diff --git a/README.md b/README.md index beac795..cbf5541 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,10 @@ A comprehensive Rust client library for the Redis Cloud REST API, with Python bi ```toml [dependencies] -redis-cloud = "0.8" +redis-cloud = "0.9.5" # Optional: Enable Tower service integration -redis-cloud = { version = "0.8", features = ["tower-integration"] } +redis-cloud = { version = "0.9.5", features = ["tower-integration"] } ``` ## Quick Start diff --git a/python/Cargo.lock b/python/Cargo.lock index 3be16ed..24f0bae 100644 --- a/python/Cargo.lock +++ b/python/Cargo.lock @@ -62,6 +62,28 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "aws-lc-rs" +version = "1.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec6fb3fe69024a75fa7e1bfb48aa6cf59706a101658ea01bfd33b2b248a038f" +dependencies = [ + "aws-lc-sys", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f50037ee5e1e41e7b8f9d161680a725bd1626cb6f8c7e901f91f942850852fe7" +dependencies = [ + "cc", + "cmake", + "dunce", + "fs_extra", +] + [[package]] name = "base64" version = "0.22.1" @@ -70,9 +92,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" [[package]] name = "bumpalo" @@ -93,9 +115,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583" dependencies = [ "find-msvc-tools", + "jobserver", + "libc", "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" version = "1.0.4" @@ -122,6 +152,35 @@ dependencies = [ "windows-link", ] +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -139,6 +198,12 @@ dependencies = [ "syn", ] +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + [[package]] name = "errno" version = "0.3.14" @@ -164,6 +229,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures" version = "0.3.31" @@ -360,7 +431,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", ] [[package]] @@ -544,6 +614,60 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + [[package]] name = "js-sys" version = "0.3.85" @@ -644,6 +768,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + [[package]] name = "parking_lot" version = "0.12.5" @@ -808,7 +938,7 @@ dependencies = [ "rustc-hash", "rustls", "socket2", - "thiserror", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -820,6 +950,7 @@ version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ + "aws-lc-rs", "bytes", "getrandom 0.3.4", "lru-slab", @@ -829,7 +960,7 @@ dependencies = [ "rustls", "rustls-pki-types", "slab", - "thiserror", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -895,7 +1026,7 @@ dependencies = [ [[package]] name = "redis-cloud" -version = "0.8.0" +version = "0.9.5" dependencies = [ "anyhow", "async-stream", @@ -907,7 +1038,7 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", - "thiserror", + "thiserror 2.0.18", "tokio", "tracing", "typed-builder", @@ -916,7 +1047,7 @@ dependencies = [ [[package]] name = "redis-cloud-py" -version = "0.1.0" +version = "0.9.5" dependencies = [ "pyo3", "pyo3-async-runtimes", @@ -924,7 +1055,7 @@ dependencies = [ "redis-cloud", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", "tokio", ] @@ -939,9 +1070,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.28" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ "base64", "bytes", @@ -961,9 +1092,9 @@ dependencies = [ "quinn", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper", "tokio", "tokio-rustls", @@ -974,7 +1105,6 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", ] [[package]] @@ -1003,14 +1133,26 @@ version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ + "aws-lc-rs", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.14.0" @@ -1021,12 +1163,40 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -1039,10 +1209,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] -name = "ryu" -version = "1.0.22" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] [[package]] name = "scopeguard" @@ -1050,6 +1232,29 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "serde" version = "1.0.228" @@ -1104,18 +1309,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "shlex" version = "1.3.0" @@ -1203,13 +1396,33 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1430,6 +1643,16 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1534,14 +1757,23 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "1.0.5" +name = "webpki-root-certs" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" dependencies = [ "rustls-pki-types", ] +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -1601,6 +1833,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1628,6 +1869,21 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1661,6 +1917,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -1673,6 +1935,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -1685,6 +1953,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1709,6 +1983,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -1721,6 +2001,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -1733,6 +2019,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -1745,6 +2037,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.52.6" diff --git a/python/Cargo.toml b/python/Cargo.toml index cceede7..fc05f99 100644 --- a/python/Cargo.toml +++ b/python/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "redis-cloud-py" -version = "0.9.3" +version = "0.9.5" edition = "2024" rust-version = "1.89" authors = ["Josh Rotenberg "] diff --git a/python/src/client.rs b/python/src/client.rs index 4c7d0a5..3d6dbf1 100644 --- a/python/src/client.rs +++ b/python/src/client.rs @@ -59,7 +59,7 @@ impl PyCloudClient { .or_else(|_| std::env::var("REDIS_CLOUD_USER_KEY")) .map_err(|_| { pyo3::exceptions::PyValueError::new_err( - "API secret not found. Set REDIS_CLOUD_API_SECRET", + "API secret not found. Set REDIS_CLOUD_API_SECRET, REDIS_CLOUD_SECRET_KEY, or REDIS_CLOUD_USER_KEY", ) })?; diff --git a/python/tests/test_client.py b/python/tests/test_client.py index 6a03914..688ed21 100644 --- a/python/tests/test_client.py +++ b/python/tests/test_client.py @@ -63,7 +63,10 @@ def test_from_env_missing_api_secret(self): os.environ.pop(var, None) try: - with pytest.raises(ValueError, match="API secret not found"): + with pytest.raises( + ValueError, + match="REDIS_CLOUD_API_SECRET, REDIS_CLOUD_SECRET_KEY, or REDIS_CLOUD_USER_KEY", + ): CloudClient.from_env() finally: os.environ.pop("REDIS_CLOUD_API_KEY", None) diff --git a/src/connectivity/mod.rs b/src/connectivity/mod.rs index 4a809a0..bfe291d 100644 --- a/src/connectivity/mod.rs +++ b/src/connectivity/mod.rs @@ -29,7 +29,9 @@ pub use private_link::PrivateLinkHandler; // Re-export PrivateLink types pub use private_link::{ - PrincipalType, PrivateLinkAddPrincipalRequest, PrivateLinkCreateRequest, + PrincipalType, PrivateLinkActiveActiveConnectionsDisassociateRequest, + PrivateLinkAddPrincipalRequest, PrivateLinkConnectionDisassociate, + PrivateLinkConnectionsDisassociateRequest, PrivateLinkCreateRequest, PrivateLinkRemovePrincipalRequest, }; pub use psc::PscHandler; @@ -37,7 +39,7 @@ pub use transit_gateway::TransitGatewayHandler; pub use vpc_peering::VpcPeeringHandler; // Re-export types used by handlers -pub use psc::PscEndpointUpdateRequest; +pub use psc::{PscEndpointCreateRequest, PscEndpointUpdateRequest}; pub use transit_gateway::{Cidr, TgwAttachmentRequest, TgwUpdateCidrsRequest}; pub use vpc_peering::{ ActiveActiveVpcPeering, ActiveActiveVpcPeeringList, ActiveActiveVpcRegion, VpcCidr, VpcPeering, @@ -131,16 +133,19 @@ impl ConnectivityHandler { pub async fn delete_psc_service( &self, subscription_id: i32, - ) -> crate::Result { + ) -> crate::Result { self.psc.delete_service(subscription_id).await } pub async fn create_psc_endpoint( &self, subscription_id: i32, - request: &PscEndpointUpdateRequest, + psc_service_id: i32, + request: &PscEndpointCreateRequest, ) -> crate::Result { - self.psc.create_endpoint(subscription_id, request).await + self.psc + .create_endpoint(subscription_id, psc_service_id, request) + .await } // Transit Gateway delegation methods @@ -201,11 +206,12 @@ impl ConnectivityHandler { pub async fn update_psc_service_endpoint( &self, subscription_id: i32, + psc_service_id: i32, endpoint_id: i32, request: &PscEndpointUpdateRequest, ) -> crate::Result { self.psc - .update_endpoint(subscription_id, endpoint_id, request) + .update_endpoint(subscription_id, psc_service_id, endpoint_id, request) .await } diff --git a/src/connectivity/private_link.rs b/src/connectivity/private_link.rs index fa2efe8..5ec6fd8 100644 --- a/src/connectivity/private_link.rs +++ b/src/connectivity/private_link.rs @@ -122,6 +122,54 @@ pub struct PrivateLinkRemovePrincipalRequest { pub alias: Option, } +/// PrivateLink connection to disassociate +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PrivateLinkConnectionDisassociate { + /// Resource share association ID + pub association_id: String, + + /// Optional VPC endpoint connection ID + #[serde(skip_serializing_if = "Option::is_none")] + pub connection_id: Option, + + /// Connection type + #[serde(rename = "type")] + pub connection_type: String, + + /// Principal that owns the connection + pub principal_id: String, +} + +/// Request to disassociate one or more PrivateLink connections +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PrivateLinkConnectionsDisassociateRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub subscription_id: Option, + + pub connections: Vec, + + #[serde(skip_serializing_if = "Option::is_none")] + pub command_type: Option, +} + +/// Request to disassociate connections from an Active-Active PrivateLink region +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PrivateLinkActiveActiveConnectionsDisassociateRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub subscription_id: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub region_id: Option, + + pub connections: Vec, + + #[serde(skip_serializing_if = "Option::is_none")] + pub command_type: Option, +} + /// `PrivateLink` configuration response #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -356,7 +404,23 @@ impl PrivateLinkHandler { self.client .delete_with_body( &format!("/subscriptions/{subscription_id}/private-link/principals"), - serde_json::to_value(request).unwrap_or_default(), + serde_json::to_value(request).map_err(crate::CloudError::from)?, + ) + .await + } + + /// Disassociate connections from `PrivateLink` + /// + /// POST /subscriptions/{subscriptionId}/private-link/connections/disassociate + pub async fn disassociate_connections( + &self, + subscription_id: i32, + request: &PrivateLinkConnectionsDisassociateRequest, + ) -> Result { + self.client + .post( + &format!("/subscriptions/{subscription_id}/private-link/connections/disassociate"), + request, ) .await } @@ -509,7 +573,7 @@ impl PrivateLinkHandler { &format!( "/subscriptions/{subscription_id}/regions/{region_id}/private-link/principals" ), - serde_json::to_value(request).unwrap_or_default(), + serde_json::to_value(request).map_err(crate::CloudError::from)?, ) .await } @@ -539,4 +603,38 @@ impl PrivateLinkHandler { )) .await } + + /// Delete Active-Active `PrivateLink` + /// + /// DELETE /subscriptions/{subscriptionId}/regions/{regionId}/private-link + pub async fn delete_active_active( + &self, + subscription_id: i32, + region_id: i32, + ) -> Result { + self.client + .delete_raw(&format!( + "/subscriptions/{subscription_id}/regions/{region_id}/private-link" + )) + .await + } + + /// Disassociate connections from Active-Active `PrivateLink` + /// + /// POST /subscriptions/{subscriptionId}/regions/{regionId}/private-link/connections/disassociate + pub async fn disassociate_connections_active_active( + &self, + subscription_id: i32, + region_id: i32, + request: &PrivateLinkActiveActiveConnectionsDisassociateRequest, + ) -> Result { + self.client + .post( + &format!( + "/subscriptions/{subscription_id}/regions/{region_id}/private-link/connections/disassociate" + ), + request, + ) + .await + } } diff --git a/src/connectivity/psc.rs b/src/connectivity/psc.rs index b08f7b5..d33c900 100644 --- a/src/connectivity/psc.rs +++ b/src/connectivity/psc.rs @@ -6,14 +6,27 @@ use crate::{CloudClient, Result}; use serde::{Deserialize, Serialize}; +/// Private Service Connect endpoint create request +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PscEndpointCreateRequest { + /// Google Cloud project ID + pub gcp_project_id: String, + + /// Name of the Google Cloud VPC that hosts your application + pub gcp_vpc_name: String, + + /// Name of your VPC's subnet of IP address ranges + pub gcp_vpc_subnet_name: String, + + /// Prefix used to create PSC endpoints in the consumer application VPC + pub endpoint_connection_name: String, +} + /// Private Service Connect endpoint update request #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub struct PscEndpointUpdateRequest { - pub subscription_id: i32, - pub psc_service_id: i32, - pub endpoint_id: i32, - /// Google Cloud project ID #[serde(skip_serializing_if = "Option::is_none")] pub gcp_project_id: Option, @@ -29,6 +42,10 @@ pub struct PscEndpointUpdateRequest { /// Prefix used to create PSC endpoints in the consumer application VPC #[serde(skip_serializing_if = "Option::is_none")] pub endpoint_connection_name: Option, + + /// Action to perform on the endpoint + #[serde(skip_serializing_if = "Option::is_none")] + pub action: Option, } /// Task state update response @@ -174,13 +191,14 @@ impl PscHandler { // ======================================================================== /// Delete Private Service Connect service - pub async fn delete_service(&self, subscription_id: i32) -> Result { - self.client - .delete(&format!( + pub async fn delete_service(&self, subscription_id: i32) -> Result { + let response = self + .client + .delete_raw(&format!( "/subscriptions/{subscription_id}/private-service-connect" )) .await?; - Ok(serde_json::Value::Null) + serde_json::from_value(response).map_err(crate::CloudError::from) } /// Get Private Service Connect service @@ -203,10 +221,14 @@ impl PscHandler { } /// Get Private Service Connect endpoints - pub async fn get_endpoints(&self, subscription_id: i32) -> Result { + pub async fn get_endpoints( + &self, + subscription_id: i32, + psc_service_id: i32, + ) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/private-service-connect/endpoints" + "/subscriptions/{subscription_id}/private-service-connect/{psc_service_id}" )) .await } @@ -215,11 +237,14 @@ impl PscHandler { pub async fn create_endpoint( &self, subscription_id: i32, - request: &PscEndpointUpdateRequest, + psc_service_id: i32, + request: &PscEndpointCreateRequest, ) -> Result { self.client .post( - &format!("/subscriptions/{subscription_id}/private-service-connect/endpoints"), + &format!( + "/subscriptions/{subscription_id}/private-service-connect/{psc_service_id}" + ), request, ) .await @@ -229,25 +254,26 @@ impl PscHandler { pub async fn delete_endpoint( &self, subscription_id: i32, + psc_service_id: i32, endpoint_id: i32, - ) -> Result { - self.client - .delete(&format!( - "/subscriptions/{subscription_id}/private-service-connect/endpoints/{endpoint_id}" + ) -> Result { + let response = self + .client + .delete_raw(&format!( + "/subscriptions/{subscription_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}" )) .await?; - Ok(serde_json::Value::Null) + serde_json::from_value(response).map_err(crate::CloudError::from) } /// Update Private Service Connect endpoint pub async fn update_endpoint( &self, subscription_id: i32, + psc_service_id: i32, endpoint_id: i32, request: &PscEndpointUpdateRequest, ) -> Result { - // Use psc_service_id from request - let psc_service_id = request.psc_service_id; self.client .put( &format!( @@ -262,11 +288,12 @@ impl PscHandler { pub async fn get_endpoint_creation_script( &self, subscription_id: i32, + psc_service_id: i32, endpoint_id: i32, - ) -> Result { + ) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/private-service-connect/endpoints/{endpoint_id}/creationScripts" + "/subscriptions/{subscription_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}/creationScripts" )) .await } @@ -275,11 +302,12 @@ impl PscHandler { pub async fn get_endpoint_deletion_script( &self, subscription_id: i32, + psc_service_id: i32, endpoint_id: i32, - ) -> Result { + ) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/private-service-connect/endpoints/{endpoint_id}/deletionScripts" + "/subscriptions/{subscription_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}/deletionScripts" )) .await } @@ -292,20 +320,26 @@ impl PscHandler { pub async fn delete_service_active_active( &self, subscription_id: i32, - ) -> Result { - self.client - .delete(&format!( - "/subscriptions/{subscription_id}/regions/private-service-connect" + region_id: i32, + ) -> Result { + let response = self + .client + .delete_raw(&format!( + "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect" )) .await?; - Ok(serde_json::Value::Null) + serde_json::from_value(response).map_err(crate::CloudError::from) } /// Get Active-Active PSC service - pub async fn get_service_active_active(&self, subscription_id: i32) -> Result { + pub async fn get_service_active_active( + &self, + subscription_id: i32, + region_id: i32, + ) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/regions/private-service-connect" + "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect" )) .await } @@ -314,10 +348,13 @@ impl PscHandler { pub async fn create_service_active_active( &self, subscription_id: i32, + region_id: i32, ) -> Result { self.client .post( - &format!("/subscriptions/{subscription_id}/regions/private-service-connect"), + &format!( + "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect" + ), &serde_json::json!({}), ) .await @@ -327,10 +364,12 @@ impl PscHandler { pub async fn get_endpoints_active_active( &self, subscription_id: i32, + region_id: i32, + psc_service_id: i32, ) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/regions/private-service-connect/endpoints" + "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}" )) .await } @@ -339,12 +378,14 @@ impl PscHandler { pub async fn create_endpoint_active_active( &self, subscription_id: i32, - request: &PscEndpointUpdateRequest, + region_id: i32, + psc_service_id: i32, + request: &PscEndpointCreateRequest, ) -> Result { self.client .post( &format!( - "/subscriptions/{subscription_id}/regions/private-service-connect/endpoints" + "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}" ), request, ) @@ -356,14 +397,16 @@ impl PscHandler { &self, subscription_id: i32, region_id: i32, + psc_service_id: i32, endpoint_id: i32, - ) -> Result { - self.client - .delete(&format!( - "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/endpoints/{endpoint_id}" + ) -> Result { + let response = self + .client + .delete_raw(&format!( + "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}" )) .await?; - Ok(serde_json::Value::Null) + serde_json::from_value(response).map_err(crate::CloudError::from) } /// Update Active-Active PSC endpoint @@ -371,13 +414,14 @@ impl PscHandler { &self, subscription_id: i32, region_id: i32, + psc_service_id: i32, endpoint_id: i32, request: &PscEndpointUpdateRequest, ) -> Result { self.client .put( &format!( - "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{subscription_id}/endpoints/{endpoint_id}" + "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}" ), request, ) @@ -391,7 +435,7 @@ impl PscHandler { region_id: i32, psc_service_id: i32, endpoint_id: i32, - ) -> Result { + ) -> Result { self.client .get(&format!( "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}/creationScripts" @@ -406,7 +450,7 @@ impl PscHandler { region_id: i32, psc_service_id: i32, endpoint_id: i32, - ) -> Result { + ) -> Result { self.client .get(&format!( "/subscriptions/{subscription_id}/regions/{region_id}/private-service-connect/{psc_service_id}/endpoints/{endpoint_id}/deletionScripts" diff --git a/src/connectivity/transit_gateway.rs b/src/connectivity/transit_gateway.rs index 358b1af..b880ef2 100644 --- a/src/connectivity/transit_gateway.rs +++ b/src/connectivity/transit_gateway.rs @@ -148,7 +148,7 @@ impl TransitGatewayHandler { pub async fn get_shared_invitations(&self, subscription_id: i32) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/tgw/shared-invitations" + "/subscriptions/{subscription_id}/transitGateways/invitations" )) .await } @@ -160,9 +160,9 @@ impl TransitGatewayHandler { invitation_id: String, ) -> Result { self.client - .post( + .put( &format!( - "/subscriptions/{subscription_id}/tgw/shared-invitations/{invitation_id}/accept" + "/subscriptions/{subscription_id}/transitGateways/invitations/{invitation_id}/accept" ), &serde_json::json!({}), ) @@ -176,9 +176,9 @@ impl TransitGatewayHandler { invitation_id: String, ) -> Result { self.client - .post( + .put( &format!( - "/subscriptions/{subscription_id}/tgw/shared-invitations/{invitation_id}/reject" + "/subscriptions/{subscription_id}/transitGateways/invitations/{invitation_id}/reject" ), &serde_json::json!({}), ) @@ -225,9 +225,16 @@ impl TransitGatewayHandler { subscription_id: i32, request: &TgwAttachmentRequest, ) -> Result { + let tgw_id = request + .tgw_id + .as_deref() + .ok_or_else(|| crate::CloudError::BadRequest { + message: "tgw_id is required".to_string(), + })?; + self.client .post( - &format!("/subscriptions/{subscription_id}/transitGateways/attachments"), + &format!("/subscriptions/{subscription_id}/transitGateways/{tgw_id}/attachment"), request, ) .await @@ -258,10 +265,11 @@ impl TransitGatewayHandler { pub async fn get_attachments_active_active( &self, subscription_id: i32, + region_id: i32, ) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/regions/transitGateways" + "/subscriptions/{subscription_id}/regions/{region_id}/transitGateways" )) .await } @@ -270,10 +278,11 @@ impl TransitGatewayHandler { pub async fn get_shared_invitations_active_active( &self, subscription_id: i32, + region_id: i32, ) -> Result { self.client .get(&format!( - "/subscriptions/{subscription_id}/regions/tgw/shared-invitations" + "/subscriptions/{subscription_id}/regions/{region_id}/transitGateways/invitations" )) .await } @@ -286,9 +295,9 @@ impl TransitGatewayHandler { invitation_id: String, ) -> Result { self.client - .post( + .put( &format!( - "/subscriptions/{subscription_id}/regions/{region_id}/tgw/shared-invitations/{invitation_id}/accept" + "/subscriptions/{subscription_id}/regions/{region_id}/transitGateways/invitations/{invitation_id}/accept" ), &serde_json::json!({}), ) @@ -303,9 +312,9 @@ impl TransitGatewayHandler { invitation_id: String, ) -> Result { self.client - .post( + .put( &format!( - "/subscriptions/{subscription_id}/regions/{region_id}/tgw/shared-invitations/{invitation_id}/reject" + "/subscriptions/{subscription_id}/regions/{region_id}/transitGateways/invitations/{invitation_id}/reject" ), &serde_json::json!({}), ) @@ -321,7 +330,7 @@ impl TransitGatewayHandler { ) -> Result { self.client .delete(&format!( - "/subscriptions/{subscription_id}/regions/{region_id}/tgw/attachments/{attachment_id}" + "/subscriptions/{subscription_id}/regions/{region_id}/transitGateways/{attachment_id}/attachment" )) .await?; Ok(serde_json::Value::Null) @@ -334,9 +343,18 @@ impl TransitGatewayHandler { region_id: i32, request: &TgwAttachmentRequest, ) -> Result { + let tgw_id = request + .tgw_id + .as_deref() + .ok_or_else(|| crate::CloudError::BadRequest { + message: "tgw_id is required".to_string(), + })?; + self.client .post( - &format!("/subscriptions/{subscription_id}/regions/{region_id}/tgw/attachments"), + &format!( + "/subscriptions/{subscription_id}/regions/{region_id}/transitGateways/{tgw_id}/attachment" + ), request, ) .await @@ -353,7 +371,7 @@ impl TransitGatewayHandler { self.client .put( &format!( - "/subscriptions/{subscription_id}/regions/{region_id}/tgw/attachments/{attachment_id}/cidrs" + "/subscriptions/{subscription_id}/regions/{region_id}/transitGateways/{attachment_id}/attachment" ), request, ) diff --git a/src/connectivity/vpc_peering.rs b/src/connectivity/vpc_peering.rs index 52f7840..42b5bc8 100644 --- a/src/connectivity/vpc_peering.rs +++ b/src/connectivity/vpc_peering.rs @@ -316,48 +316,62 @@ impl VpcPeeringHandler { // Active-Active VPC Peering // ======================================================================== // - // Note: Active-Active VPC peering uses the same API endpoints as standard - // VPC peering. These methods are provided for API consistency and to match - // the naming convention used by other connectivity handlers. + // Note: Active-Active VPC peering uses dedicated `/regions/peerings` + // endpoints in the current REST API. /// Get Active-Active VPC peerings /// - /// Note: Uses the same endpoint as standard VPC peering. pub async fn get_active_active(&self, subscription_id: i32) -> Result { - self.get(subscription_id).await + self.client + .get(&format!( + "/subscriptions/{subscription_id}/regions/peerings" + )) + .await } /// Create Active-Active VPC peering /// - /// Note: Uses the same endpoint as standard VPC peering. pub async fn create_active_active( &self, subscription_id: i32, request: &VpcPeeringCreateRequest, ) -> Result { - self.create(subscription_id, request).await + self.client + .post( + &format!("/subscriptions/{subscription_id}/regions/peerings"), + request, + ) + .await } /// Delete Active-Active VPC peering /// - /// Note: Uses the same endpoint as standard VPC peering. pub async fn delete_active_active( &self, subscription_id: i32, peering_id: i32, ) -> Result { - self.delete(subscription_id, peering_id).await + self.client + .delete(&format!( + "/subscriptions/{subscription_id}/regions/peerings/{peering_id}" + )) + .await?; + Ok(serde_json::Value::Null) } /// Update Active-Active VPC peering /// - /// Note: Uses the same endpoint as standard VPC peering. pub async fn update_active_active( &self, subscription_id: i32, peering_id: i32, request: &VpcPeeringCreateRequest, ) -> Result { - self.update(subscription_id, peering_id, request).await + self.client + .put( + &format!("/subscriptions/{subscription_id}/regions/peerings/{peering_id}"), + request, + ) + .await } } diff --git a/src/flexible/subscriptions.rs b/src/flexible/subscriptions.rs index fd4d1d9..4d46bf4 100644 --- a/src/flexible/subscriptions.rs +++ b/src/flexible/subscriptions.rs @@ -58,6 +58,8 @@ use serde_json::Value; use std::collections::HashMap; use typed_builder::TypedBuilder; +pub use crate::types::CloudTag as ResourceTag; + // ============================================================================ // Models // ============================================================================ @@ -233,6 +235,19 @@ pub struct CidrAllowlistUpdateRequest { pub command_type: Option, } +/// Update subscription resource tags +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SubscriptionResourceTagsUpdateRequest { + #[serde(skip_serializing_if = "Option::is_none")] + pub subscription_id: Option, + + pub resource_tags: Vec, + + #[serde(skip_serializing_if = "Option::is_none")] + pub command_type: Option, +} + /// `SubscriptionMaintenanceWindowsSpec` #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SubscriptionMaintenanceWindowsSpec { @@ -1050,6 +1065,23 @@ impl SubscriptionHandler { .await } + /// Update Pro subscription resource tags + /// Replaces all existing resource tags on the specified Pro subscription. + /// + /// PUT /subscriptions/{subscriptionId}/resource-tags + pub async fn update_subscription_resource_tags( + &self, + subscription_id: i32, + request: &SubscriptionResourceTagsUpdateRequest, + ) -> Result { + self.client + .put( + &format!("/subscriptions/{subscription_id}/resource-tags"), + request, + ) + .await + } + /// Get Pro subscription pricing /// Gets pricing details for the specified Pro subscription. /// @@ -1072,13 +1104,12 @@ impl SubscriptionHandler { subscription_id: i32, request: &ActiveActiveRegionDeleteRequest, ) -> Result { - // TODO: DELETE with body not yet supported by client - let _ = request; // Suppress unused variable warning - let response = self - .client - .delete_raw(&format!("/subscriptions/{subscription_id}/regions")) - .await?; - serde_json::from_value(response).map_err(Into::into) + self.client + .delete_with_body( + &format!("/subscriptions/{subscription_id}/regions"), + serde_json::to_value(request).map_err(crate::CloudError::from)?, + ) + .await } /// Get regions in an Active-Active subscription diff --git a/src/lib.rs b/src/lib.rs index 5839b42..e371573 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,7 +330,12 @@ pub use connectivity::psc::PscHandler; pub use connectivity::transit_gateway::TransitGatewayHandler; pub use connectivity::vpc_peering::VpcPeeringHandler; // Connectivity types -pub use connectivity::{PrincipalType, PrivateLinkAddPrincipalRequest, PrivateLinkCreateRequest}; +pub use connectivity::{ + PrincipalType, PrivateLinkActiveActiveConnectionsDisassociateRequest, + PrivateLinkAddPrincipalRequest, PrivateLinkConnectionDisassociate, + PrivateLinkConnectionsDisassociateRequest, PrivateLinkCreateRequest, + PrivateLinkRemovePrincipalRequest, +}; // Legacy connectivity export for backward compatibility pub use connectivity::ConnectivityHandler; diff --git a/tests/connectivity_tests.rs b/tests/connectivity_tests.rs index 0966f7b..b5145ec 100644 --- a/tests/connectivity_tests.rs +++ b/tests/connectivity_tests.rs @@ -1,4 +1,4 @@ -use redis_cloud::{CloudClient, ConnectivityHandler}; +use redis_cloud::{CloudClient, ConnectivityHandler, PscHandler}; use serde_json::json; use wiremock::matchers::{header, method, path}; use wiremock::{Mock, MockServer, ResponseTemplate}; @@ -163,6 +163,74 @@ async fn test_create_psc_service() { assert_eq!(result.command_type, Some("CREATE_PSC_SERVICE".to_string())); } +#[tokio::test] +async fn test_get_psc_endpoints() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path("/subscriptions/123/private-service-connect/789")) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-get-psc-endpoints", + "commandType": "GET_PSC_SERVICE_ENDPOINTS", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler.get_endpoints(123, 789).await.unwrap(); + + assert_eq!(result.task_id, Some("task-get-psc-endpoints".to_string())); +} + +#[tokio::test] +async fn test_create_psc_endpoint() { + let mock_server = MockServer::start().await; + + Mock::given(method("POST")) + .and(path("/subscriptions/123/private-service-connect/789")) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-create-psc-endpoint", + "commandType": "CREATE_PSC_SERVICE_ENDPOINT", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = ConnectivityHandler::new(client); + let request = redis_cloud::connectivity::PscEndpointCreateRequest { + gcp_project_id: "project1".to_string(), + gcp_vpc_name: "vpc1".to_string(), + gcp_vpc_subnet_name: "subnet1".to_string(), + endpoint_connection_name: "psc-endpoint".to_string(), + }; + + let result = handler + .create_psc_endpoint(123, 789, &request) + .await + .unwrap(); + + assert_eq!(result.task_id, Some("task-create-psc-endpoint".to_string())); +} + #[tokio::test] async fn test_get_tgws() { let mock_server = MockServer::start().await; @@ -326,6 +394,35 @@ async fn test_create_vpc_peering_azure() { assert_eq!(result.command_type, Some("CREATE_VPC_PEERING".to_string())); } +#[tokio::test] +async fn test_get_active_active_vpc_peering() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path("/subscriptions/123/regions/peerings")) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "taskId": "task-get-aa-peering", + "commandType": "GET_ACTIVE_ACTIVE_VPC_PEERING", + "status": "processing-completed" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = redis_cloud::VpcPeeringHandler::new(client); + let result = handler.get_active_active(123).await.unwrap(); + + assert_eq!(result.task_id, Some("task-get-aa-peering".to_string())); +} + #[tokio::test] async fn test_update_psc_service() { let mock_server = MockServer::start().await; @@ -354,23 +451,126 @@ async fn test_update_psc_service() { let handler = ConnectivityHandler::new(client); let request = redis_cloud::connectivity::PscEndpointUpdateRequest { - subscription_id: 123, - psc_service_id: 789, - endpoint_id: 1, gcp_project_id: Some("project1".to_string()), gcp_vpc_name: Some("vpc1".to_string()), gcp_vpc_subnet_name: Some("subnet1".to_string()), endpoint_connection_name: Some("psc-endpoint".to_string()), + action: None, }; let result = handler - .update_psc_service_endpoint(123, 1, &request) + .update_psc_service_endpoint(123, 789, 1, &request) .await .unwrap(); assert_eq!(result.task_id, Some("task-update-psc".to_string())); assert_eq!(result.command_type, Some("UPDATE_PSC_SERVICE".to_string())); } +#[tokio::test] +async fn test_get_psc_endpoint_creation_script() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path( + "/subscriptions/123/private-service-connect/789/endpoints/1/creationScripts", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-get-psc-creation-script", + "commandType": "GET_PSC_SERVICE_ENDPOINT_CREATION_SCRIPT", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler + .get_endpoint_creation_script(123, 789, 1) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-get-psc-creation-script".to_string()) + ); +} + +#[tokio::test] +async fn test_get_psc_endpoint_deletion_script() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path( + "/subscriptions/123/private-service-connect/789/endpoints/1/deletionScripts", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-get-psc-deletion-script", + "commandType": "GET_PSC_SERVICE_ENDPOINT_DELETION_SCRIPT", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler + .get_endpoint_deletion_script(123, 789, 1) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-get-psc-deletion-script".to_string()) + ); +} + +#[tokio::test] +async fn test_delete_psc_endpoint() { + let mock_server = MockServer::start().await; + + Mock::given(method("DELETE")) + .and(path( + "/subscriptions/123/private-service-connect/789/endpoints/1", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-delete-psc-endpoint", + "commandType": "DELETE_PSC_SERVICE_ENDPOINT", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler.delete_endpoint(123, 789, 1).await.unwrap(); + + assert_eq!(result.task_id, Some("task-delete-psc-endpoint".to_string())); +} + #[tokio::test] async fn test_delete_psc_service() { let mock_server = MockServer::start().await; @@ -398,8 +598,263 @@ async fn test_delete_psc_service() { let handler = ConnectivityHandler::new(client); let result = handler.delete_psc_service(123).await.unwrap(); - // Delete methods now return serde_json::Value::Null - assert_eq!(result, serde_json::Value::Null); + assert_eq!(result.task_id, Some("task-delete-psc".to_string())); +} + +#[tokio::test] +async fn test_get_active_active_psc_service() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path( + "/subscriptions/123/regions/27/private-service-connect", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-get-aa-psc", + "commandType": "GET_ACTIVE_ACTIVE_PSC_SERVICE", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler.get_service_active_active(123, 27).await.unwrap(); + + assert_eq!(result.task_id, Some("task-get-aa-psc".to_string())); +} + +#[tokio::test] +async fn test_create_active_active_psc_service() { + let mock_server = MockServer::start().await; + + Mock::given(method("POST")) + .and(path( + "/subscriptions/123/regions/27/private-service-connect", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-create-aa-psc", + "commandType": "CREATE_ACTIVE_ACTIVE_PSC_SERVICE", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler.create_service_active_active(123, 27).await.unwrap(); + + assert_eq!(result.task_id, Some("task-create-aa-psc".to_string())); +} + +#[tokio::test] +async fn test_delete_active_active_psc_service() { + let mock_server = MockServer::start().await; + + Mock::given(method("DELETE")) + .and(path( + "/subscriptions/123/regions/27/private-service-connect", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-delete-aa-psc", + "commandType": "DELETE_ACTIVE_ACTIVE_PSC_SERVICE", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler.delete_service_active_active(123, 27).await.unwrap(); + + assert_eq!(result.task_id, Some("task-delete-aa-psc".to_string())); +} + +#[tokio::test] +async fn test_get_active_active_psc_endpoints() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path( + "/subscriptions/123/regions/27/private-service-connect/789", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-get-aa-psc-endpoints", + "commandType": "GET_ACTIVE_ACTIVE_PSC_SERVICE_ENDPOINTS", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler + .get_endpoints_active_active(123, 27, 789) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-get-aa-psc-endpoints".to_string()) + ); +} + +#[tokio::test] +async fn test_create_active_active_psc_endpoint() { + let mock_server = MockServer::start().await; + + Mock::given(method("POST")) + .and(path( + "/subscriptions/123/regions/27/private-service-connect/789", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-create-aa-psc-endpoint", + "commandType": "CREATE_ACTIVE_ACTIVE_PSC_SERVICE_ENDPOINT", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let request = redis_cloud::connectivity::PscEndpointCreateRequest { + gcp_project_id: "project1".to_string(), + gcp_vpc_name: "vpc1".to_string(), + gcp_vpc_subnet_name: "subnet1".to_string(), + endpoint_connection_name: "psc-endpoint".to_string(), + }; + + let result = handler + .create_endpoint_active_active(123, 27, 789, &request) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-create-aa-psc-endpoint".to_string()) + ); +} + +#[tokio::test] +async fn test_update_active_active_psc_endpoint() { + let mock_server = MockServer::start().await; + + Mock::given(method("PUT")) + .and(path( + "/subscriptions/123/regions/27/private-service-connect/789/endpoints/1", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-update-aa-psc-endpoint", + "commandType": "UPDATE_ACTIVE_ACTIVE_PSC_SERVICE_ENDPOINT", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let request = redis_cloud::connectivity::PscEndpointUpdateRequest { + gcp_project_id: Some("project1".to_string()), + gcp_vpc_name: Some("vpc1".to_string()), + gcp_vpc_subnet_name: Some("subnet1".to_string()), + endpoint_connection_name: Some("psc-endpoint".to_string()), + action: Some("accept".to_string()), + }; + + let result = handler + .update_endpoint_active_active(123, 27, 789, 1, &request) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-update-aa-psc-endpoint".to_string()) + ); +} + +#[tokio::test] +async fn test_delete_active_active_psc_endpoint() { + let mock_server = MockServer::start().await; + + Mock::given(method("DELETE")) + .and(path( + "/subscriptions/123/regions/27/private-service-connect/789/endpoints/1", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-delete-aa-psc-endpoint", + "commandType": "DELETE_ACTIVE_ACTIVE_PSC_SERVICE_ENDPOINT", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PscHandler::new(client); + let result = handler + .delete_endpoint_active_active(123, 27, 789, 1) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-delete-aa-psc-endpoint".to_string()) + ); } #[tokio::test] @@ -442,6 +897,69 @@ async fn test_create_tgw() { ); } +#[tokio::test] +async fn test_get_tgw_shared_invitations() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path("/subscriptions/123/transitGateways/invitations")) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "taskId": "task-get-tgw-invitations", + "commandType": "GET_TGW_SHARED_INVITATIONS", + "status": "processing-completed" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = redis_cloud::TransitGatewayHandler::new(client); + let result = handler.get_shared_invitations(123).await.unwrap(); + + assert_eq!(result.task_id, Some("task-get-tgw-invitations".to_string())); +} + +#[tokio::test] +async fn test_accept_tgw_resource_share() { + let mock_server = MockServer::start().await; + + Mock::given(method("PUT")) + .and(path( + "/subscriptions/123/transitGateways/invitations/invite-456/accept", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-accept-tgw-share", + "commandType": "ACCEPT_TGW_RESOURCE_SHARE", + "status": "processing-in-progress" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = redis_cloud::TransitGatewayHandler::new(client); + let result = handler + .accept_resource_share(123, "invite-456".to_string()) + .await + .unwrap(); + + assert_eq!(result.task_id, Some("task-accept-tgw-share".to_string())); +} + #[tokio::test] async fn test_update_tgw() { let mock_server = MockServer::start().await; @@ -490,6 +1008,43 @@ async fn test_update_tgw() { ); } +#[tokio::test] +async fn test_get_active_active_tgw_shared_invitations() { + let mock_server = MockServer::start().await; + + Mock::given(method("GET")) + .and(path( + "/subscriptions/123/regions/7/transitGateways/invitations", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(200).set_body_json(json!({ + "taskId": "task-get-aa-tgw-invitations", + "commandType": "GET_ACTIVE_ACTIVE_TGW_SHARED_INVITATIONS", + "status": "processing-completed" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = redis_cloud::TransitGatewayHandler::new(client); + let result = handler + .get_shared_invitations_active_active(123, 7) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-get-aa-tgw-invitations".to_string()) + ); +} + #[tokio::test] async fn test_delete_tgw() { let mock_server = MockServer::start().await; diff --git a/tests/fixtures/cloud_openapi.json b/tests/fixtures/cloud_openapi.json index a64a2ce..1488cf8 100644 --- a/tests/fixtures/cloud_openapi.json +++ b/tests/fixtures/cloud_openapi.json @@ -22,7 +22,8 @@ "security": [ { "x-api-key": [], - "x-api-secret-key": [] + "x-api-secret-key": [], + "x-auth-token": [] } ], "tags": [ @@ -99,12 +100,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -165,12 +166,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -227,12 +228,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -291,12 +292,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -357,12 +358,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -419,12 +420,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -503,12 +504,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -575,12 +576,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -650,12 +651,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -724,12 +725,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -798,12 +799,86 @@ } ], "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, "412": { "description": "Precondition Failed - Feature flag for this flow is off" }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/resource-tags": { + "put": { + "tags": [ + "Subscriptions - Pro" + ], + "summary": "Update Pro subscription resource tags", + "description": "Updates the resource tags for the specified Pro subscription. This replaces all existing tags with the provided tags.", + "operationId": "updateSubscriptionResourceTags", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscriptionResourceTagsUpdateRequest" + } + } + }, + "required": true + }, + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -893,12 +968,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -976,12 +1051,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1062,12 +1137,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1147,12 +1222,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1251,12 +1326,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1343,12 +1418,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1433,12 +1508,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -1505,12 +1580,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -1599,12 +1674,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1681,12 +1756,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1771,12 +1846,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1843,12 +1918,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -1907,12 +1982,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -1973,12 +2048,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2049,12 +2124,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2142,12 +2217,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2214,12 +2289,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2288,12 +2363,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2364,12 +2439,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2446,12 +2521,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2542,12 +2617,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2624,12 +2699,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2728,12 +2803,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2812,12 +2887,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -2861,7 +2936,7 @@ "Subscriptions - Pro" ], "summary": "Get Pro subscription CIDR whitelist", - "description": "(Self-hosted AWS subscriptions only) Gets a Pro subscription's CIDR whitelist.", + "description": "(Bring your own Cloud only) Gets a Pro subscription's CIDR whitelist. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getCidrWhiteList", "parameters": [ { @@ -2876,12 +2951,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -2917,7 +2992,7 @@ "Subscriptions - Pro" ], "summary": "Update Pro subscription CIDR whitelist", - "description": "(Self-hosted AWS subscriptions only) Updates a Pro subscription's CIDR whitelist.", + "description": "(Bring your own Cloud only) Updates a Pro subscription's CIDR whitelist.", "operationId": "updateSubscriptionCidrWhiteList", "parameters": [ { @@ -2942,12 +3017,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -3027,12 +3102,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -3091,12 +3166,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3156,12 +3231,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -3218,12 +3293,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3294,12 +3369,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3383,12 +3458,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3455,12 +3530,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3529,12 +3604,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3605,12 +3680,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3687,12 +3762,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3783,12 +3858,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3865,12 +3940,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3930,12 +4005,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -3997,12 +4072,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -4060,12 +4135,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4125,12 +4200,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4191,12 +4266,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4253,12 +4328,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4327,12 +4402,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -4389,12 +4464,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4463,12 +4538,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -4525,12 +4600,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -4577,12 +4652,12 @@ "description": "Gets a list of all Pro subscriptions in the current account.", "operationId": "getAllSubscriptions", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4632,6 +4707,7 @@ "deploymentType": "single-region", "paymentMethod": "credit-card", "paymentMethodId": 12345, + "publicEndpointAccess": true, "memoryStorage": "ram", "cloudProviders": [ { @@ -4673,12 +4749,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -4740,12 +4816,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4806,12 +4882,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4878,12 +4954,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -4927,7 +5003,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get Private Service Connect for a single region", - "description": "(Active-Active subscriptions only) Gets Private Service Connect details for a single region in an Active-Active subscription.", + "description": "(Active-Active subscriptions only) Gets Private Service Connect details for a single region in an Active-Active subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getActiveActivePscService", "parameters": [ { @@ -4952,12 +5028,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5018,12 +5094,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5093,12 +5169,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5142,7 +5218,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get Private Service Connect endpoints for a single region", - "description": "(Active-Active subscriptions only) Gets endpoint details for the specified Private Service Connect in a single region in an Active-Active subscription.", + "description": "(Active-Active subscriptions only) Gets endpoint details for the specified Private Service Connect in a single region in an Active-Active subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getActiveActivePscServiceEndpoints", "parameters": [ { @@ -5177,12 +5253,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5263,12 +5339,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5309,14 +5385,14 @@ } } }, - "/subscriptions/{subscriptionId}/regions/peerings": { + "/subscriptions/{subscriptionId}/regions/{regionId}/private-link": { "get": { "tags": [ "Subscriptions - Pro - Connectivity" ], - "summary": "Get Active-Active VPC peering details", - "description": "(Active-Active subscriptions only) Gets VPC peering details for an Active-Active subscription.", - "operationId": "getActiveActiveVpcPeerings", + "summary": "Get Private Link configuration for a specific region", + "description": "(Active-Active subscriptions only) Gets the Private Link configuration for a specific region. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", + "operationId": "getActiveActivePrivateLink", "parameters": [ { "name": "subscriptionId", @@ -5327,17 +5403,28 @@ "type": "integer", "format": "int32" } + }, + { + "name": "regionId", + "in": "path", + "description": "Region ID - required for Active-Active subscription", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1 } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, - "200": { - "description": "OK", + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", "content": { "application/json": { "schema": { @@ -5370,9 +5457,9 @@ "tags": [ "Subscriptions - Pro - Connectivity" ], - "summary": "Create Active-Active VPC peering", - "description": "(Active-Active subscriptions only) Sets up VPC peering for an Active-Active subscription. Ensure your cloud provider is also set up for VPC Peering with Redis Cloud. See [VPC Peering](https://docs.redis.com/latest/rc/security/vpc-peering) to learn how to set up VPC Peering with AWS and Google Cloud.", - "operationId": "createActiveActiveVpcPeering", + "summary": "Create a Private Link for a specific region", + "description": "(Active-Active subscriptions only) Creates a new Private Link for a specific region.", + "operationId": "createActiveActivePrivateLink", "parameters": [ { "name": "subscriptionId", @@ -5383,14 +5470,487 @@ "type": "integer", "format": "int32" } - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ActiveActiveVpcPeeringCreateBaseRequest" - }, + }, + { + "name": "regionId", + "in": "path", + "description": "Region ID - required for Active-Active subscription", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateLinkActiveActiveCreateRequest" + } + } + }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" + }, + "422": { + "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "delete": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Delete Private Link for a specific region", + "description": "(Active-Active subscriptions only) Deletes the Private Link configuration for a specific region.", + "operationId": "deleteActiveActivePrivateLink", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "regionId", + "in": "path", + "description": "Region ID - required for Active-Active subscription", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1 + } + ], + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/regions/{regionId}/private-link/principals": { + "post": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Add principal to Private Link for a specific region", + "description": "(Active-Active subscriptions only) Adds a principal (AWS ARN) to the Private Link configuration for a specific region.", + "operationId": "createActiveActivePrivateLinkPrincipal", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "regionId", + "in": "path", + "description": "Region ID - required for Active-Active subscription", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateLinkActiveActivePrincipalsCreateRequest" + } + } + }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" + }, + "422": { + "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "delete": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Remove a principal from Private Link for a specific region", + "description": "(Active-Active subscriptions only) Removes one principal (AWS ARNs) from the Private Link configuration for a specific region.", + "operationId": "deleteActiveActivePrivateLinkPrincipals", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "regionId", + "in": "path", + "description": "Region ID - required for Active-Active subscription", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateLinkActiveActivePrincipalsDeleteRequest" + } + } + }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/regions/{regionId}/private-link/connections/disassociate": { + "post": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Disassociate connections from Private Link for a specific region", + "description": "(Active-Active subscriptions only) Disassociates one or more VPC endpoint connections from the Private Link configuration for a specific region.", + "operationId": "disassociateActiveActivePrivateLinkConnections", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "regionId", + "in": "path", + "description": "Region ID - required for Active-Active subscription", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1 + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateLinkActiveActiveConnectionsDisassociateRequest" + } + } + }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/regions/peerings": { + "get": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Get Active-Active VPC peering details", + "description": "(Active-Active subscriptions only) Gets VPC peering details for an Active-Active subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", + "operationId": "getActiveActiveVpcPeerings", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "post": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Create Active-Active VPC peering", + "description": "(Active-Active subscriptions only) Sets up VPC peering for an Active-Active subscription. Ensure your cloud provider is also set up for VPC Peering with Redis Cloud. See [VPC Peering](https://docs.redis.com/latest/rc/security/vpc-peering) to learn how to set up VPC Peering with AWS and Google Cloud.", + "operationId": "createActiveActiveVpcPeering", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ActiveActiveVpcPeeringCreateBaseRequest" + }, "example": { "provider": "string", "region": "us-east-1", @@ -5403,17 +5963,355 @@ } } }, - "required": true - }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" + }, + "422": { + "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/private-service-connect": { + "get": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Get Private Service Connect", + "description": "Gets Private Service Connect details for a subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", + "operationId": "getPscService", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "post": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Set up Private Service Connect for a subscription", + "description": "Sets up Google Cloud Private Service Connect for an existing subscription hosted on Google Cloud.", + "operationId": "createPscService", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" + }, + "422": { + "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "delete": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Remove Private Service Connect for a subscription", + "description": "Deletes Private Service Connect for a subscription.", + "operationId": "deletePscService", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/private-service-connect/{pscServiceId}": { + "get": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Get Private Service Connect endpoints", + "description": "Gets endpoint details for the specified Private Service Connect. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", + "operationId": "getPscServiceEndpoints", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pscServiceId", + "in": "path", + "description": "Private Service Connect service ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, "412": { "description": "Precondition Failed - Feature flag for this flow is off" }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "post": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Create a Private Service Connect endpoint", + "description": "Creates a new Private Service Connect endpoint.", + "operationId": "createPscServiceEndpoint", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "pscServiceId", + "in": "path", + "description": "Private Service Connect service ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PscEndpointCreateRequest" + } + } + }, + "required": true + }, + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, - "200": { - "description": "OK", + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", "content": { "application/json": { "schema": { @@ -5452,14 +6350,14 @@ } } }, - "/subscriptions/{subscriptionId}/private-service-connect": { + "/subscriptions/{subscriptionId}/private-link": { "get": { "tags": [ "Subscriptions - Pro - Connectivity" ], - "summary": "Get Private Service Connect", - "description": "Gets Private Service Connect details for a subscription.", - "operationId": "getPscService", + "summary": "Get Private Link configuration", + "description": "Gets the Private Link configuration for a subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", + "operationId": "getPrivateLink", "parameters": [ { "name": "subscriptionId", @@ -5473,12 +6371,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5513,9 +6411,9 @@ "tags": [ "Subscriptions - Pro - Connectivity" ], - "summary": "Set up Private Service Connect for a subscription", - "description": "Sets up Google Cloud Private Service Connect for an existing subscription hosted on Google Cloud.", - "operationId": "createPscService", + "summary": "Create a Private Link", + "description": "Creates a new Private Link.", + "operationId": "createPrivateLink", "parameters": [ { "name": "subscriptionId", @@ -5528,15 +6426,25 @@ } } ], - "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateLinkCreateRequest" + } + } }, + "required": true + }, + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, - "202": { - "description": "Accepted", + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", "content": { "application/json": { "schema": { @@ -5578,9 +6486,9 @@ "tags": [ "Subscriptions - Pro - Connectivity" ], - "summary": "Remove Private Service Connect for a subscription", - "description": "Deletes Private Service Connect for a subscription.", - "operationId": "deletePscService", + "summary": "Delete Private Link", + "description": "Deletes the Private Link configuration for a subscription.", + "operationId": "deletePrivateLink", "parameters": [ { "name": "subscriptionId", @@ -5594,14 +6502,14 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, - "202": { - "description": "Accepted", + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", "content": { "application/json": { "schema": { @@ -5637,14 +6545,14 @@ } } }, - "/subscriptions/{subscriptionId}/private-service-connect/{pscServiceId}": { - "get": { + "/subscriptions/{subscriptionId}/private-link/principals": { + "post": { "tags": [ "Subscriptions - Pro - Connectivity" ], - "summary": "Get Private Service Connect endpoints", - "description": "Gets endpoint details for the specified Private Service Connect.", - "operationId": "getPscServiceEndpoints", + "summary": "Add principal to Private Link", + "description": "Adds a principal (AWS ARN) to the Private Link configuration.", + "operationId": "createPrivateLinkPrincipal", "parameters": [ { "name": "subscriptionId", @@ -5655,11 +6563,76 @@ "type": "integer", "format": "int32" } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateLinkPrincipalsCreateRequest" + } + } + }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" + }, + "422": { + "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "delete": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Remove a principal from Private Link", + "description": "Removes a principal (AWS ARNs) from the Private Link configuration.", + "operationId": "deletePrivateLinkPrincipals", + "parameters": [ { - "name": "pscServiceId", + "name": "subscriptionId", "in": "path", - "description": "Private Service Connect service ID.", + "description": "Subscription ID.", "required": true, "schema": { "type": "integer", @@ -5667,15 +6640,25 @@ } } ], - "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PrivateLinkPrincipalsDeleteRequest" + } + } }, + "required": true + }, + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, - "202": { - "description": "Accepted", + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "204": { + "description": "No Content", "content": { "application/json": { "schema": { @@ -5693,6 +6676,12 @@ "404": { "description": "Not Found - The resource you were trying to reach was not found or does not exist" }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" + }, "429": { "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" }, @@ -5703,14 +6692,16 @@ "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " } } - }, + } + }, + "/subscriptions/{subscriptionId}/private-link/connections/disassociate": { "post": { "tags": [ "Subscriptions - Pro - Connectivity" ], - "summary": "Create a Private Service Connect endpoint", - "description": "Creates a new Private Service Connect endpoint.", - "operationId": "createPscServiceEndpoint", + "summary": "Disassociate connections from Private Link", + "description": "Disassociates one or more VPC endpoint connections from the Private Link configuration.", + "operationId": "disassociatePrivateLinkConnections", "parameters": [ { "name": "subscriptionId", @@ -5721,35 +6712,25 @@ "type": "integer", "format": "int32" } - }, - { - "name": "pscServiceId", - "in": "path", - "description": "Private Service Connect service ID.", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - } } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PscEndpointCreateRequest" + "$ref": "#/components/schemas/PrivateLinkConnectionsDisassociateRequest" } } }, "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5764,7 +6745,7 @@ "description": "Unauthorized - Authentication failed for requested resource" }, "403": { - "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" }, "404": { "description": "Not Found - The resource you were trying to reach was not found or does not exist" @@ -5773,10 +6754,7 @@ "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" }, "409": { - "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" - }, - "422": { - "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" }, "429": { "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" @@ -5796,7 +6774,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get VPC peering details", - "description": "Gets VPC peering details for the specified subscription.", + "description": "Gets VPC peering details for the specified subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getVpcPeering", "parameters": [ { @@ -5811,12 +6789,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5888,12 +6866,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -5978,12 +6956,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6062,12 +7040,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -6139,12 +7117,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6215,12 +7193,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6289,12 +7267,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6365,12 +7343,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6448,12 +7426,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6523,12 +7501,12 @@ } }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6575,12 +7553,12 @@ "description": "Gets a list of all Essentials subscriptions in the current account.", "operationId": "getAllSubscriptions_1", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6629,14 +7607,183 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, - "202": { - "description": "Accepted", + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" + }, + "422": { + "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/fixed/subscriptions/{subscriptionId}/databases": { + "get": { + "tags": [ + "Databases - Essentials" + ], + "summary": "Get all databases in an Essentials subscription", + "description": "Gets a list of all databases in the specified Essentials subscription.", + "operationId": "getFixedSubscriptionDatabases", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "minimum": 0, + "type": "integer", + "format": "int32" + } + }, + { + "name": "offset", + "in": "query", + "description": "Number of items to skip.", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 0 + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of items to return.", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 100 + } + ], + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AccountFixedSubscriptionDatabases" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + }, + "post": { + "tags": [ + "Databases - Essentials" + ], + "summary": "Create Essentials database", + "description": "Creates a new database in the specified Essentials subscription.", + "operationId": "createFixedDatabase", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FixedDatabaseCreateRequest" + }, + "example": { + "name": "Redis-fixed-database-example", + "protocol": "stack", + "dataPersistence": "none", + "dataEvictionPolicy": "allkeys-lru", + "replication": true, + "alerts": [ + { + "name": "datasets-size", + "value": 80 + } + ] + } + } + }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "200": { + "description": "OK", "content": { "application/json": { "schema": { @@ -6675,14 +7822,14 @@ } } }, - "/fixed/subscriptions/{subscriptionId}/databases": { + "/fixed/subscriptions/{subscriptionId}/databases/{databaseId}/upgrade": { "get": { "tags": [ "Databases - Essentials" ], - "summary": "Get all databases in an Essentials subscription", - "description": "Gets a list of all databases in the specified Essentials subscription.", - "operationId": "getFixedSubscriptionDatabases", + "summary": "Get Essentials database version upgrade status", + "description": "Gets information on the latest upgrade attempt for this Essentials database.", + "operationId": "getEssentialsDatabaseRedisVersionUpgradeStatus", "parameters": [ { "name": "subscriptionId", @@ -6690,47 +7837,34 @@ "description": "Subscription ID.", "required": true, "schema": { - "minimum": 0, "type": "integer", "format": "int32" } }, { - "name": "offset", - "in": "query", - "description": "Number of items to skip.", - "required": false, - "schema": { - "type": "integer", - "format": "int32" - }, - "example": 0 - }, - { - "name": "limit", - "in": "query", - "description": "Maximum number of items to return.", - "required": false, + "name": "databaseId", + "in": "path", + "description": "Database ID.", + "required": true, "schema": { "type": "integer", "format": "int32" - }, - "example": 100 + } } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AccountFixedSubscriptionDatabases" + "$ref": "#/components/schemas/BdbVersionUpgradeStatus" } } } @@ -6759,9 +7893,9 @@ "tags": [ "Databases - Essentials" ], - "summary": "Create Essentials database", - "description": "Creates a new database in the specified Essentials subscription.", - "operationId": "createFixedDatabase", + "summary": "Upgrade Essentials database version", + "description": "Upgrades the specified Essentials database to a later Redis version.", + "operationId": "upgradeEssentialsDatabaseRedisVersion", "parameters": [ { "name": "subscriptionId", @@ -6772,38 +7906,35 @@ "type": "integer", "format": "int32" } + }, + { + "name": "databaseId", + "in": "path", + "description": "Database ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/FixedDatabaseCreateRequest" - }, - "example": { - "name": "Redis-fixed-database-example", - "protocol": "stack", - "dataPersistence": "none", - "dataEvictionPolicy": "allkeys-lru", - "replication": true, - "alerts": [ - { - "name": "datasets-size", - "value": 80 - } - ] + "$ref": "#/components/schemas/FixedDatabaseUpgradeRedisVersionRequest" } } }, "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6818,7 +7949,7 @@ "description": "Unauthorized - Authentication failed for requested resource" }, "403": { - "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" }, "404": { "description": "Not Found - The resource you were trying to reach was not found or does not exist" @@ -6827,10 +7958,7 @@ "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" }, "409": { - "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" - }, - "422": { - "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with new updated name)" }, "429": { "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" @@ -6875,12 +8003,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -6951,12 +8079,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7025,12 +8153,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7100,12 +8228,12 @@ } }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7143,6 +8271,71 @@ } } }, + "/cost-report": { + "post": { + "tags": [ + "Account" + ], + "summary": "Generate cost report", + "description": "Generates a cost report in FOCUS format for the specified time period (max 40 days range) and filters. [Read more about focus here](https://focus.finops.org/).\n", + "operationId": "createCostReport", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CostReportCreateRequest" + } + } + }, + "required": true + }, + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to create requested resource (primarily due to not active resource)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "408": { + "description": "Request Timeout - The server didn't receive a complete request message within the server's allotted timeout period" + }, + "409": { + "description": "Conflict - request could not be processed because of a conflict (primarily due to another resource that exist with the new name" + }, + "422": { + "description": "Unprocessable Entity - The server understands the request, and the syntax of the request is correct, but it was unable to process the contained instructions" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, "/cloud-accounts": { "get": { "tags": [ @@ -7152,12 +8345,12 @@ "description": "Gets a list of all configured cloud accounts.", "operationId": "getCloudAccounts", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7206,12 +8399,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -7261,12 +8454,12 @@ "description": "Gets a list of all access control users for this account.", "operationId": "getAllUsers_1", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7315,12 +8508,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -7370,12 +8563,12 @@ "description": "Gets a list of all database access roles for this account.", "operationId": "getRoles", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7424,12 +8617,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -7479,12 +8672,12 @@ "description": "Gets a list of all Redis ACL rules for this account.", "operationId": "getAllRedisRules", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7533,12 +8726,12 @@ "required": true }, "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -7588,12 +8781,12 @@ "description": "Gets a list of all account users.", "operationId": "getAllUsers", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7634,12 +8827,12 @@ "description": "Gets a list of all currently running tasks for this account.", "operationId": "getAllTasks", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7691,12 +8884,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7734,7 +8927,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get transit gateways for a subscription", - "description": "Gets all AWS transit gateway details for the specified subscription.", + "description": "Gets all AWS transit gateway details for the specified subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getTgws", "parameters": [ { @@ -7749,12 +8942,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7792,7 +8985,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get transit gateway invitations for a subscription", - "description": "Gets all AWS transit gateway invitations for the specified subscription.", + "description": "Gets all AWS transit gateway invitations for the specified subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getTgwSharedInvitations", "parameters": [ { @@ -7807,12 +9000,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7850,7 +9043,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get transit gateways for a single region", - "description": "(Active-Active subscriptions only) Gets all AWS transit gateway details for the specified region in an Active-Active subscription.", + "description": "(Active-Active subscriptions only) Gets all AWS transit gateway details for the specified region in an Active-Active subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getActiveActiveTgws", "parameters": [ { @@ -7876,12 +9069,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7919,7 +9112,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get transit gateway invitations for a single region", - "description": "(Active-Active subscriptions only) Gets AWS transit gateway invitations for the specified region in an Active-Active subscription.", + "description": "(Active-Active subscriptions only) Gets AWS transit gateway invitations for the specified region in an Active-Active subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getActiveActiveTgwSharedInvitations", "parameters": [ { @@ -7945,12 +9138,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -7988,7 +9181,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get Private Service Connect endpoint deletion script for a single region", - "description": "(Active-Active subscriptions only) Gets the gcloud script to delete the specified Private Service Connect endpoint on Google Cloud.", + "description": "(Active-Active subscriptions only) Gets the gcloud script to delete the specified Private Service Connect endpoint on Google Cloud. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getActiveActivPscServiceEndpointDeletionScript", "parameters": [ { @@ -8033,12 +9226,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -8076,7 +9269,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get Private Service Connect endpoint creation script for a single region", - "description": "(Active-Active subscriptions only) Gets the gcloud script to create the specified Private Service Connect endpoint on Google Cloud.", + "description": "(Active-Active subscriptions only) Gets the gcloud script to create the specified Private Service Connect endpoint on Google Cloud. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getActiveActivPscServiceEndpointCreationScript", "parameters": [ { @@ -8121,12 +9314,80 @@ } ], "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, "412": { "description": "Precondition Failed - Feature flag for this flow is off" }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/regions/{regionId}/private-link/endpoint-script": { + "get": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Get Private Link endpoint script for a single region", + "description": "(Active-Active subscriptions only) Gets the Private Link endpoint script for a single region in an Active-Active subscription. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", + "operationId": "getActiveActivePrivateLinkEndpointScript", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "regionId", + "in": "path", + "description": "Region ID - required for Active-Active subscription", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -8164,7 +9425,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get Private Service Connect endpoint deletion script", - "description": "Gets the gcloud script to delete the specified Private Service Connect endpoint on Google Cloud.", + "description": "Gets the gcloud script to delete the specified Private Service Connect endpoint on Google Cloud. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getPscServiceEndpointDeletionScript", "parameters": [ { @@ -8199,12 +9460,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -8242,7 +9503,7 @@ "Subscriptions - Pro - Connectivity" ], "summary": "Get Private Service Connect endpoint creation script", - "description": "Gets the gcloud script to create the specified Private Service Connect endpoint on Google Cloud.", + "description": "Gets the gcloud script to create the specified Private Service Connect endpoint on Google Cloud. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", "operationId": "getPscServiceEndpointCreationScript", "parameters": [ { @@ -8277,12 +9538,70 @@ } ], "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, "412": { "description": "Precondition Failed - Feature flag for this flow is off" }, + "202": { + "description": "Accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TaskStateUpdate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/private-link/endpoint-script": { + "get": { + "tags": [ + "Subscriptions - Pro - Connectivity" + ], + "summary": "Get Private Link endpoint script", + "description": "Gets the Python discovery script for Private Link. Internal users can optionally request a Terraform snippet. [Asynchronous operation](https://redis.io/docs/latest/operate/rc/api/get-started/process-lifecycle/) - Query [GET /tasks/{taskId}](#tag/Tasks/operation/getTaskById) with the returned taskId.", + "operationId": "getPrivateLinkEndpointScript", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "202": { "description": "Accepted", "content": { @@ -8335,12 +9654,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8412,12 +9731,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8482,18 +9801,86 @@ } ], "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, "412": { "description": "Precondition Failed - Feature flag for this flow is off" }, + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseCertificate" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/subscriptions/{subscriptionId}/databases/{databaseId}/available-target-versions": { + "get": { + "tags": [ + "Databases - Pro" + ], + "summary": "Get available upgrade versions for Pro database", + "description": "Gets a list of available Redis versions that the specified Pro database can be upgraded to.", + "operationId": "getDatabaseAvailableVersions", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "databaseId", + "in": "path", + "description": "Database ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatabaseCertificate" + "$ref": "#/components/schemas/BdbAvailableVersionsResponse" } } } @@ -8540,12 +9927,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8609,15 +9996,35 @@ "format": "int32" }, "example": 100 + }, + { + "name": "startTime", + "in": "query", + "description": "Filter session logs with time >= startTime (UTC)", + "required": false, + "schema": { + "type": "string" + }, + "example": "2025-01-01T00:00:00Z" + }, + { + "name": "endTime", + "in": "query", + "description": "Filter session logs with time <= endTime (UTC)", + "required": false, + "schema": { + "type": "string" + }, + "example": "2025-01-31T23:59:59Z" } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8655,7 +10062,7 @@ "Account" ], "summary": "Get available Pro plan regions", - "description": "Gets a list of available regions for Pro subscriptions. For Essentials subscriptions, use 'GET /fixed/plans'.", + "description": "Gets a list of available regions for Pro subscriptions. For Essentials subscriptions, use [GET /fixed/plans](#tag/Subscriptions-Essentials/operation/getAllFixedSubscriptionsPlans).", "operationId": "getSupportedRegions", "parameters": [ { @@ -8673,12 +10080,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8718,13 +10125,13 @@ "summary": "Get query performance factors", "description": "Gets a list of available [query performance factors](https://redis.io/docs/latest/operate/rc/databases/configuration/advanced-capabilities/#query-performance-factor).", "operationId": "getSupportedSearchScalingFactors", - "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8765,12 +10172,12 @@ "description": "Gets a list of all payment methods for this account.", "operationId": "getAccountPaymentMethods", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8834,15 +10241,46 @@ "format": "int32" }, "example": 100 + }, + { + "name": "startTime", + "in": "query", + "description": "Filter logs with time >= startTime (UTC)", + "required": false, + "schema": { + "type": "string" + }, + "example": "2025-01-01T00:00:00Z" + }, + { + "name": "endTime", + "in": "query", + "description": "Filter logs with time <= endTime (UTC)", + "required": false, + "schema": { + "type": "string" + }, + "example": "2025-01-31T23:59:59Z" + }, + { + "name": "resourceId", + "in": "query", + "description": "Filter logs by resourceId", + "required": false, + "schema": { + "type": "integer", + "format": "int32" + }, + "example": 1234 } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -8905,18 +10343,86 @@ } ], "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, "412": { "description": "Precondition Failed - Feature flag for this flow is off" }, + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseSlowLogEntries" + } + } + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, + "/fixed/subscriptions/{subscriptionId}/databases/{databaseId}/available-target-versions": { + "get": { + "tags": [ + "Databases - Essentials" + ], + "summary": "Get available upgrade versions for Essentials database", + "description": "Gets a list of available Redis versions that the specified Essentials database can be upgraded to.", + "operationId": "getEssentialsDatabaseAvailableVersions", + "parameters": [ + { + "name": "subscriptionId", + "in": "path", + "description": "Subscription ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "databaseId", + "in": "path", + "description": "Database ID.", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DatabaseSlowLogEntries" + "$ref": "#/components/schemas/BdbAvailableVersionsResponse" } } } @@ -8963,12 +10469,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -9034,12 +10540,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -9092,12 +10598,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -9150,12 +10656,12 @@ } ], "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -9193,15 +10699,15 @@ "Account" ], "summary": "Get advanced capabilities", - "description": "Gets a list of Redis [advanced capabilities](https://redis.io/docs/latest/operate/rc/databases/configuration/advanced-capabilities/) (also known as modules) available for this account. Advanced capability support may differ based on subscription and database settings.", + "description": "Gets a list of Redis [advanced capabilities](https://redis.io/docs/latest/operate/rc/databases/configuration/advanced-capabilities/) (also known as modules) available for databases prior to Redis 8. Advanced capability support may differ based on subscription and database settings.", "operationId": "getSupportedDatabaseModules", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -9242,12 +10748,12 @@ "description": "Gets a list of all [data persistence](https://redis.io/docs/latest/operate/rc/databases/configuration/data-persistence/) options for this account.", "operationId": "getDataPersistenceOptions", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -9279,6 +10785,60 @@ } } }, + "/cost-report/{costReportId}": { + "get": { + "tags": [ + "Account" + ], + "summary": "Get cost report", + "description": "Returns the generated cost report file in FOCUS format using the costReportId returned from the cost report generation task. The file is downloaded as an attachment with the filename set to the costReportId.", + "operationId": "getCostReport", + "parameters": [ + { + "name": "costReportId", + "in": "path", + "description": "Cost Report ID. Returned from a Cost Report generation task.", + "required": true, + "schema": { + "type": "string" + }, + "example": "cost-report-12345-abcdef" + } + ], + "responses": { + "400": { + "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" + }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, + "200": { + "description": "Returns the cost report file", + "content": { + "application/octet-stream": {} + } + }, + "401": { + "description": "Unauthorized - Authentication failed for requested resource" + }, + "403": { + "description": "Forbidden - Not allowed to access requested resource (primarily due to client source IP API Key restrictions)" + }, + "404": { + "description": "Not Found - The resource you were trying to reach was not found or does not exist" + }, + "429": { + "description": "Too Many Requests - Too many resources are concurrently created / updated / deleted in the account. Please re-submit API requests after resource changes are completed)" + }, + "500": { + "description": "Internal system error - If this error persists, please contact customer support" + }, + "503": { + "description": "Service Unavailable - Server is temporarily unable to handle the request, please try again later. If this error persists, please contact customer support " + } + } + } + }, "/": { "get": { "tags": [ @@ -9288,12 +10848,12 @@ "description": "Gets information on this account.", "operationId": "getCurrentAccount", "responses": { - "412": { - "description": "Precondition Failed - Feature flag for this flow is off" - }, "400": { "description": "Bad Request - The server cannot process the request due to something that is perceived to be a client error" }, + "412": { + "description": "Precondition Failed - Feature flag for this flow is off" + }, "200": { "description": "OK", "content": { @@ -9328,6 +10888,14 @@ }, "components": { "schemas": { + "TargetVersion": { + "type": "object", + "properties": { + "redisVersion": { + "type": "string" + } + } + }, "AclUserCreateRequest": { "required": [ "name", @@ -9344,12 +10912,12 @@ "role": { "type": "string", "description": "Name of the database access role to assign to this user. Use GET '/acl/roles' to get a list of database access roles.", - "example": "Redis-role-example" + "example": "ACL-role-example" }, "password": { "type": "string", "description": "The database password for this user.", - "example": "some-random-password" + "example": "ab123AB$%^" }, "commandType": { "type": "string", @@ -9430,7 +10998,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -9510,7 +11078,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -9518,7 +11086,7 @@ "example": { "account": { "id": 1001, - "name": "Redis Labs", + "name": "Redis", "createdTimestamp": "2018-12-23T15:15:31Z", "updatedTimestamp": "2022-10-12T10:54:10Z", "pocStatus": "inactive", @@ -9526,7 +11094,7 @@ "key": { "name": "capi-api-key-name", "accountId": 1001, - "accountName": "Redis Labs", + "accountName": "Redis", "allowedSourceIps": [ "0.0.0.0/0" ], @@ -9541,6 +11109,63 @@ } } }, + "PrivateLinkActiveActiveCreateRequest": { + "required": [ + "principal", + "regionId", + "shareName", + "type" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "regionId": { + "type": "integer", + "description": "Deployment region id as defined by cloud provider", + "format": "int32", + "readOnly": true + }, + "shareName": { + "maxLength": 64, + "minLength": 0, + "type": "string", + "description": "Name for the resource share", + "example": "my-private-link-share" + }, + "principal": { + "type": "string", + "description": "AWS account ID or ARN of the principal (IAM user, role, or account)", + "example": "123456789012" + }, + "type": { + "type": "string", + "description": "Type of the principal", + "example": "aws_account", + "enum": [ + "aws_account", + "organization", + "organization_unit", + "iam_role", + "iam_user", + "service_principal" + ] + }, + "alias": { + "type": "string", + "description": "Alias or friendly name for the principal", + "example": "Production Account" + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Request to create a private link for Active-Active subscription" + }, "ActiveActiveVpcPeeringCreateAwsRequest": { "required": [ "awsAccountId", @@ -9617,17 +11242,21 @@ }, "paymentMethodId": { "type": "integer", - "description": "Optional. The payment method ID you'd like to use for this subscription. Must be a valid payment method ID for this account. Use GET /payment-methods to get all payment methods for your account. This value is optional if ‘paymentMethod’ is ‘marketplace’, but required if 'paymentMethod' is 'credit-card'.", + "description": "Optional. The payment method ID you'd like to use for this subscription. Must be a valid payment method ID for this account. Use GET /payment-methods to get all payment methods for your account. This value is optional if \u2018paymentMethod\u2019 is \u2018marketplace\u2019, but required if 'paymentMethod' is 'credit-card'.", "format": "int32" }, "paymentMethod": { "type": "string", - "description": "Optional. The payment method for the subscription. If set to ‘credit-card’ , ‘paymentMethodId’ must be defined.", + "description": "Optional. The payment method for the subscription. If set to \u2018credit-card\u2019 , \u2018paymentMethodId\u2019 must be defined.", "enum": [ "credit-card", "marketplace" ] }, + "publicEndpointAccess": { + "type": "boolean", + "description": "Optional. When 'false', all databases on this subscription will reject any connection attempt to the public endpoint and any connection attempt to the private endpoint that does not come from an IP address in the private address space defined in [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918#section-3 ). You must use a [private connectivity method](https://redis.io/docs/latest/operate/rc/security/database-security/block-public-endpoints/#private-connectivity-methods ) to connect to a database with a blocked public endpoint." + }, "commandType": { "type": "string", "readOnly": true @@ -9757,7 +11386,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -9775,7 +11404,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -9878,6 +11507,12 @@ "memcached" ] }, + "port": { + "type": "integer", + "description": "Optional. TCP port on which the database is available (10000-19999). Generated automatically if not set.", + "format": "int32", + "example": 10000 + }, "memoryLimitInGb": { "minimum": 0.1, "exclusiveMinimum": false, @@ -9891,7 +11526,7 @@ "minimum": 0.1, "exclusiveMinimum": false, "type": "number", - "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb.If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.", + "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If \u2018replication\u2019 is 'true', the database\u2019s total memory will be twice as large as the datasetSizeInGb.If \u2018replication\u2019 is false, the database\u2019s total memory will be the datasetSizeInGb value.", "format": "double", "example": 1 }, @@ -9928,7 +11563,7 @@ }, "modules": { "type": "array", - "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities.", + "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities. Don't specify modules for database versions 8 and above. All capabilities are bundled in the database by default.", "items": { "$ref": "#/components/schemas/DatabaseModuleSpec" } @@ -9941,8 +11576,15 @@ }, "averageItemSizeInBytes": { "type": "integer", - "description": "Optional. Relevant only to ram-and-flash (also known as Auto Tiering) subscriptions. Estimated average size in bytes of the items stored in the database. Default: 1000", - "format": "int64" + "description": "Optional. Relevant only to ram-and-flash (also known as Redis-Flex/Auto-Tiering) subscriptions. Estimated average size in bytes of the items stored in the database. Default: 1000", + "format": "int64", + "deprecated": true + }, + "ramPercentage": { + "type": "integer", + "description": "Optional. Relevant only to ram-and-flash (also known as Redis-Flex/Auto-Tiering) subscriptions. The percentage of data to be stored in RAM. Must be between 10 and 50 in steps of 10 (10, 20, 30, 40, 50). Default: 20", + "format": "int32", + "example": 20 }, "respVersion": { "type": "string", @@ -9958,6 +11600,10 @@ "description": "Optional. If specified, redisVersion defines the Redis database version. If omitted, the Redis version will be set to the default version (available in 'GET /subscriptions/redis-versions')", "example": "7.2" }, + "autoMinorVersionUpgrade": { + "type": "boolean", + "description": "Optional. Automatically upgrades the database to newer minor versions within the same major release. Applies to version 8.4 and above. Default: true." + }, "shardingType": { "type": "string", "description": "Optional. Database [Hashing policy](https://redis.io/docs/latest/operate/rc/databases/configuration/clustering/#manage-the-hashing-policy).", @@ -9992,6 +11638,9 @@ "status": { "type": "string" }, + "publicEndpointAccess": { + "type": "boolean" + }, "memoryStorage": { "type": "string", "enum": [ @@ -10015,7 +11664,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } }, @@ -10036,6 +11685,7 @@ "status": "active", "deploymentType": "single-region", "paymentMethodId": 2, + "publicEndpointAccess": true, "memoryStorage": "ram", "numberOfDatabases": 6, "paymentMethodType": "credit-card", @@ -10152,7 +11802,7 @@ "minimum": 0.1, "exclusiveMinimum": false, "type": "number", - "description": "(Pay-as-you-go subscriptions only) Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb. If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.", + "description": "(Pay-as-you-go subscriptions only) Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If \u2018replication\u2019 is 'true', the database\u2019s total memory will be twice as large as the datasetSizeInGb. If \u2018replication\u2019 is false, the database\u2019s total memory will be the datasetSizeInGb value.", "format": "double", "example": 1 }, @@ -10283,7 +11933,7 @@ }, "modules": { "type": "array", - "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities. Can only be set if 'protocol' is 'redis'.", + "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities. Can only be set if 'protocol' is 'redis'. Don't specify modules for database versions 8 and above. All capabilities are bundled in the database by default.", "items": { "$ref": "#/components/schemas/DatabaseModuleSpec" } @@ -10331,7 +11981,7 @@ "minimum": 0.1, "exclusiveMinimum": false, "type": "number", - "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb.If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.", + "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If \u2018replication\u2019 is 'true', the database\u2019s total memory will be twice as large as the datasetSizeInGb.If \u2018replication\u2019 is false, the database\u2019s total memory will be the datasetSizeInGb value.", "format": "double", "example": 1 }, @@ -10466,6 +12116,16 @@ "$ref": "#/components/schemas/DatabaseAlertSpec" } }, + "ramPercentage": { + "type": "integer", + "description": "Optional. Relevant only to ram-and-flash (also known as Redis-Flex/Auto-Tiering) subscriptions. The percentage of data to be stored in RAM. Must be between 10 and 50 in steps of 10 (10, 20, 30, 40, 50).", + "format": "int32", + "example": 20 + }, + "autoMinorVersionUpgrade": { + "type": "boolean", + "description": "Optional. Automatically upgrades the database to newer minor versions within the same major release. Applies to version 8.4 and above." + }, "commandType": { "type": "string", "readOnly": true @@ -10531,6 +12191,10 @@ "resp2", "resp3" ] + }, + "enableDefaultUser": { + "type": "boolean", + "description": "Optional. When 'true', allows connecting to the database with the 'default' user. When 'false', only defined access control users can connect to the database. If set, 'globalEnableDefaultUser' will not apply to this region." } }, "description": "Optional. A list of regions and local settings to update." @@ -10653,7 +12317,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -10661,148 +12325,289 @@ "example": { "regions": [ { + "id": 1, "name": "us-east-1", "provider": "AWS" }, { + "id": 2, "name": "us-west-1", "provider": "AWS" }, { + "id": 3, "name": "us-west-2", "provider": "AWS" }, { + "id": 4, "name": "eu-west-1", "provider": "AWS" }, { + "id": 29, "name": "eu-central-1", "provider": "AWS" }, { - "name": "ap-northeast-1", + "id": 7, + "name": "sa-east-1", "provider": "AWS" }, { - "name": "ap-southeast-1", + "id": 63, + "name": "ca-central-1", "provider": "AWS" }, { - "name": "ap-southeast-2", + "id": 62, + "name": "eu-north-1", "provider": "AWS" }, { - "name": "sa-east-1", + "id": 61, + "name": "eu-west-3", + "provider": "AWS" + }, + { + "id": 60, + "name": "eu-west-2", "provider": "AWS" }, { + "id": 59, "name": "us-east-2", "provider": "AWS" }, { - "name": "eu-west-2", + "id": 64, + "name": "ap-east-1", "provider": "AWS" }, { - "name": "eu-west-3", + "id": 146, + "name": "ap-southeast-5", "provider": "AWS" }, { - "name": "eu-north-1", + "id": 30, + "name": "ap-south-1", "provider": "AWS" }, { - "name": "ca-central-1", + "id": 117, + "name": "ap-northeast-3", "provider": "AWS" }, { - "name": "ap-east-1", + "id": 116, + "name": "ap-northeast-2", "provider": "AWS" }, { - "name": "ap-south-1", + "id": 145, + "name": "ap-southeast-7", + "provider": "AWS" + }, + { + "id": 6, + "name": "ap-northeast-1", + "provider": "AWS" + }, + { + "id": 5, + "name": "ap-southeast-1", "provider": "AWS" }, { + "id": 15, + "name": "ap-southeast-2", + "provider": "AWS" + }, + { + "id": 132, + "name": "il-central-1", + "provider": "AWS" + }, + { + "id": 144, + "name": "mx-central-1", + "provider": "AWS" + }, + { + "id": 32, "name": "asia-east1", "provider": "GCP" }, { + "id": 67, "name": "asia-east2", "provider": "GCP" }, { + "id": 33, "name": "asia-northeast1", "provider": "GCP" }, { + "id": 104, "name": "asia-northeast2", "provider": "GCP" }, { + "id": 69, "name": "asia-south1", "provider": "GCP" }, { + "id": 34, "name": "asia-southeast1", "provider": "GCP" }, { + "id": 71, "name": "australia-southeast1", "provider": "GCP" }, { + "id": 72, "name": "europe-north1", "provider": "GCP" }, { + "id": 35, "name": "europe-west1", "provider": "GCP" }, { + "id": 74, "name": "europe-west2", "provider": "GCP" }, { + "id": 128, + "name": "asia-southeast2", + "provider": "GCP" + }, + { + "id": 75, "name": "europe-west3", "provider": "GCP" }, { + "id": 36, "name": "europe-west4", "provider": "GCP" }, { + "id": 133, + "name": "europe-west10", + "provider": "GCP" + }, + { + "id": 130, + "name": "europe-southwest1", + "provider": "GCP" + }, + { + "id": 134, + "name": "europe-west8", + "provider": "GCP" + }, + { + "id": 113, "name": "europe-west6", "provider": "GCP" }, { + "id": 129, + "name": "me-west1", + "provider": "GCP" + }, + { + "id": 135, + "name": "europe-west9", + "provider": "GCP" + }, + { + "id": 77, "name": "northamerica-northeast1", "provider": "GCP" }, { - "name": "southamerica-east1", + "id": 136, + "name": "europe-west12", + "provider": "GCP" + }, + { + "id": 137, + "name": "europe-central2", "provider": "GCP" }, { + "id": 131, + "name": "northamerica-northeast2", + "provider": "GCP" + }, + { + "id": 138, + "name": "me-central2", + "provider": "GCP" + }, + { + "id": 139, + "name": "me-central1", + "provider": "GCP" + }, + { + "id": 140, + "name": "us-east5", + "provider": "GCP" + }, + { + "id": 141, + "name": "us-south1", + "provider": "GCP" + }, + { + "id": 27, "name": "us-central1", "provider": "GCP" }, { + "id": 38, "name": "us-east1", "provider": "GCP" }, { + "id": 39, "name": "us-east4", "provider": "GCP" }, { + "id": 40, "name": "us-west1", "provider": "GCP" }, { + "id": 82, "name": "us-west2", "provider": "GCP" + }, + { + "id": 142, + "name": "southamerica-west1", + "provider": "GCP" + }, + { + "id": 95, + "name": "southamerica-east1", + "provider": "GCP" + }, + { + "id": 143, + "name": "africa-south1", + "provider": "GCP" } ] } @@ -10815,7 +12620,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -10955,7 +12760,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -10966,7 +12771,7 @@ "cloudAccounts": [ { "id": 1, - "name": "Redis Labs Internal Resources", + "name": "Redis Internal Resources", "provider": "AWS", "status": "active", "links": [] @@ -10997,6 +12802,85 @@ ] } }, + "PrivateLinkActiveActivePrincipalsCreateRequest": { + "required": [ + "principal", + "regionId" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "regionId": { + "type": "integer", + "description": "Deployment region id as defined by cloud provider", + "format": "int32", + "readOnly": true + }, + "principal": { + "type": "string", + "description": "AWS account ID or ARN of the principal (IAM user, role, or account)", + "example": "123456789012" + }, + "type": { + "type": "string", + "description": "Type of the principal", + "example": "aws_account", + "enum": [ + "aws_account", + "organization", + "organization_unit", + "iam_role", + "iam_user", + "service_principal" + ] + }, + "alias": { + "type": "string", + "description": "Alias or friendly name for the principal", + "example": "Production Account" + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Request to add a principal to private link for Active-Active subscription" + }, + "PrivateLinkActiveActiveConnectionsDisassociateRequest": { + "required": [ + "connections" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "regionId": { + "type": "integer", + "description": "Deployment region id as defined by cloud provider", + "format": "int32", + "readOnly": true + }, + "connections": { + "type": "array", + "description": "List of connections to disassociate from the private link. Each connection must include associationId, type, and principalId.", + "items": { + "$ref": "#/components/schemas/PrivateLinkConnectionDisassociate" + } + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Request to disassociate connections from private link for Active-Active subscription" + }, "VpcPeeringUpdateAwsRequest": { "type": "object", "properties": { @@ -11048,7 +12932,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -11196,7 +13080,8 @@ }, "redisRule": { "type": "string", - "description": "Optional. Changes the Redis ACL rule pattern. See [ACL syntax](https://redis.io/docs/latest/operate/rc/security/access-control/data-access-control/configure-acls/#define-permissions-with-acl-syntax) to learn how to define rules." + "description": "Optional. Changes the Redis ACL rule pattern. See [ACL syntax](https://redis.io/docs/latest/operate/rc/security/access-control/data-access-control/configure-acls/#define-permissions-with-acl-syntax) to learn how to define rules.", + "example": "+set allkeys allchannels" }, "commandType": { "type": "string", @@ -11246,12 +13131,18 @@ "signInLoginUrl": { "type": "string" }, + "awsUserArn": { + "type": "string" + }, + "awsConsoleRoleArn": { + "type": "string" + }, "links": { "type": "array", "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } }, @@ -11266,7 +13157,7 @@ "description": "RedisLabs Cloud Account information", "example": { "id": 1, - "name": "Redis Labs Internal Resources", + "name": "Redis Internal Resources", "provider": "AWS", "status": "active", "links": [ @@ -11278,6 +13169,47 @@ ] } }, + "PrivateLinkPrincipalsCreateRequest": { + "required": [ + "principal" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "principal": { + "type": "string", + "description": "AWS account ID or ARN of the principal (IAM user, role, or account)", + "example": "123456789012" + }, + "type": { + "type": "string", + "description": "Type of the principal", + "example": "aws_account", + "enum": [ + "aws_account", + "organization", + "organization_unit", + "iam_role", + "iam_user", + "service_principal" + ] + }, + "alias": { + "type": "string", + "description": "Alias or friendly name for the principal", + "example": "Production Account" + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Private Link principals create request" + }, "FixedSubscriptionUpdateRequest": { "type": "object", "properties": { @@ -11298,7 +13230,7 @@ }, "paymentMethod": { "type": "string", - "description": "Optional. The payment method for the subscription. If set to ‘credit-card’ , ‘paymentMethodId’ must be defined.", + "description": "Optional. The payment method for the subscription. If set to \u2018credit-card\u2019 , \u2018paymentMethodId\u2019 must be defined.", "enum": [ "credit-card", "marketplace" @@ -11306,7 +13238,7 @@ }, "paymentMethodId": { "type": "integer", - "description": "Optional. The payment method ID you'd like to use for this subscription. Must be a valid payment method ID for this account. Use GET /payment-methods to get a list of payment methods for your account. This value is optional if ‘paymentMethod’ is ‘marketplace’, but required if 'paymentMethod' is 'credit-card'.", + "description": "Optional. The payment method ID you'd like to use for this subscription. Must be a valid payment method ID for this account. Use GET /payment-methods to get a list of payment methods for your account. This value is optional if \u2018paymentMethod\u2019 is \u2018marketplace\u2019, but required if 'paymentMethod' is 'credit-card'.", "format": "int32" }, "commandType": { @@ -11330,7 +13262,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -11353,7 +13285,7 @@ }, "deletionGracePeriod": { "type": "string", - "description": "Optional. The grace period for deleting the subscription. If not set, will default to immediate deletion grace period.", + "description": "Optional. The grace period for deleting the subscription if Redis cannot access the provided key. Required when applying customer managed keys for a new subscription.", "example": "alerts-only", "enum": [ "alerts-only", @@ -11377,6 +13309,97 @@ }, "description": "Subscription update request message" }, + "CostReportCreateRequest": { + "required": [ + "endDate", + "startDate" + ], + "type": "object", + "properties": { + "startDate": { + "type": "string", + "description": "Filter for usage starting on or after this date. Must be in format YYYY-MM-DD", + "format": "YYYY-MM-DD", + "example": "2025-10-01" + }, + "endDate": { + "type": "string", + "description": "Filter for usage ending on or before this date. Must be in format YYYY-MM-DD and must be after start date", + "format": "YYYY-MM-DD", + "example": "2025-11-06" + }, + "format": { + "type": "string", + "description": "Output format for the cost report", + "example": "csv", + "default": "csv", + "enum": [ + "json", + "csv" + ] + }, + "subscriptionIds": { + "type": "array", + "description": "Array of subscriptionIDs to filter by", + "example": [ + 123, + 456 + ], + "items": { + "type": "integer", + "description": "Array of subscriptionIDs to filter by", + "format": "int32" + } + }, + "databaseIds": { + "type": "array", + "description": "Array of database IDs to filter by", + "example": [ + 789, + 101112 + ], + "items": { + "type": "integer", + "description": "Array of database IDs to filter by", + "format": "int32" + } + }, + "subscriptionType": { + "type": "string", + "description": "Filter by plan type", + "example": "pro", + "enum": [ + "pro", + "essentials" + ] + }, + "regions": { + "type": "array", + "description": "Array of regions to filter by", + "example": [ + "us-east-1", + "eu-west-1" + ], + "items": { + "type": "string", + "description": "Array of regions to filter by", + "example": "[\"us-east-1\",\"eu-west-1\"]" + } + }, + "tags": { + "type": "array", + "description": "Array of key-value pairs for tag filtering", + "items": { + "$ref": "#/components/schemas/Tag" + } + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Cost report generation request" + }, "AccountSubscriptionDatabases": { "type": "object", "properties": { @@ -11389,7 +13412,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -11832,6 +13855,10 @@ "resource": { "type": "string" }, + "resourceId": { + "type": "integer", + "format": "int32" + }, "type": { "type": "string" }, @@ -11849,7 +13876,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } }, @@ -11893,7 +13920,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -12017,7 +14044,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } }, @@ -12132,7 +14159,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -12144,7 +14171,7 @@ "time": "2022-10-12T10:54:31Z", "originator": "example-value", "type": "Account", - "description": "example-value (example.value@redislabs.com)'s user name was changed to Example Value" + "description": "example-value (example.value@redis.com)'s user name was changed to Example Value" }, { "id": 2900348, @@ -12253,6 +14280,18 @@ } } }, + "ResourceTag": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "description": "List of resource tags to apply to the subscription. This will replace all existing tags." + }, "CustomerManagedKeyAccessDetails": { "type": "object", "properties": { @@ -12331,7 +14370,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -12363,16 +14402,36 @@ "$ref": "#/components/schemas/AccountSessionLogEntry" } }, - "links": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": { - "type": "object" - } - } + "links": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + }, + "Tag": { + "required": [ + "key", + "value" + ], + "type": "object", + "properties": { + "key": { + "type": "string", + "description": "Tag key", + "example": "environment" + }, + "value": { + "type": "string", + "description": "Tag value", + "example": "production" } - } + }, + "description": "Tag filter for cost report" }, "AccountSubscriptions": { "type": "object", @@ -12386,7 +14445,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -12401,6 +14460,7 @@ "status": "active", "deploymentType": "single-region", "paymentMethodId": 123, + "publicEndpointAccess": true, "memoryStorage": "ram", "numberOfDatabases": 6, "paymentMethodType": "credit-card", @@ -12419,6 +14479,7 @@ "cloudDetails": [ { "provider": "AWS", + "awsAccountId": "550680565604", "cloudAccountId": 1666, "totalSizeInGb": 0.0272, "regions": [ @@ -12539,7 +14600,7 @@ "minimum": 0.1, "exclusiveMinimum": false, "type": "number", - "description": "(Pay-as-you-go subscriptions only) Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb. If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.", + "description": "(Pay-as-you-go subscriptions only) Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If \u2018replication\u2019 is 'true', the database\u2019s total memory will be twice as large as the datasetSizeInGb. If \u2018replication\u2019 is false, the database\u2019s total memory will be the datasetSizeInGb value.", "format": "double", "example": 1 }, @@ -12745,7 +14806,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -12826,7 +14887,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -12879,7 +14940,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -12960,7 +15021,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -13265,7 +15326,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -13471,7 +15532,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -13522,7 +15583,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -13577,6 +15638,17 @@ }, "description": "Database tag" }, + "BdbAvailableVersionsResponse": { + "type": "object", + "properties": { + "targets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TargetVersion" + } + } + } + }, "SubscriptionSpec": { "required": [ "regions" @@ -13604,6 +15676,13 @@ "items": { "$ref": "#/components/schemas/SubscriptionRegionSpec" } + }, + "resourceTags": { + "type": "array", + "description": "Optional. A list of resource tags to apply to the subscription. (max. 30 tags).", + "items": { + "$ref": "#/components/schemas/ResourceTag" + } } }, "description": "Cloud provider, region, and networking details." @@ -13654,7 +15733,7 @@ "example": {} } }, - "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities." + "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities. Don't specify modules for database versions 8 and above. All capabilities are bundled in the database by default." }, "FixedSubscriptionCreateRequest": { "required": [ @@ -13675,7 +15754,7 @@ }, "paymentMethod": { "type": "string", - "description": "Optional. The payment method for the subscription. If set to ‘credit-card’, ‘paymentMethodId’ must be defined. Default: 'credit-card'", + "description": "Optional. The payment method for the subscription. If set to \u2018credit-card\u2019, \u2018paymentMethodId\u2019 must be defined. Default: 'credit-card'", "enum": [ "credit-card", "marketplace" @@ -13683,7 +15762,7 @@ }, "paymentMethodId": { "type": "integer", - "description": "Optional. A valid payment method ID for this account. Use GET /payment-methods to get a list of all payment methods for your account. This value is optional if ‘paymentMethod’ is ‘marketplace’, but required for all other account types.", + "description": "Optional. A valid payment method ID for this account. Use GET /payment-methods to get a list of all payment methods for your account. This value is optional if \u2018paymentMethod\u2019 is \u2018marketplace\u2019, but required for all other account types.", "format": "int32" }, "commandType": { @@ -13709,21 +15788,43 @@ "subnetIds": { "type": "array", "description": "Optional. Enter a list of subnets identifiers that exists in the hosted AWS account. Subnet Identifier must exist within the hosting account.", - "example": "", "items": { "type": "string", - "description": "Optional. Enter a list of subnets identifiers that exists in the hosted AWS account. Subnet Identifier must exist within the hosting account.", - "example": "" + "description": "Optional. Enter a list of subnets identifiers that exists in the hosted AWS account. Subnet Identifier must exist within the hosting account." } }, "securityGroupId": { "type": "string", - "description": "Optional. Enter a security group identifier that exists in the hosted AWS account. Security group Identifier must be in a valid format (for example: 'sg-0125be68a4625884ad') and must exist within the hosting account.", - "example": "" + "description": "Optional. Enter a security group identifier that exists in the hosted AWS account. Security group Identifier must be in a valid format (for example: 'sg-0125be68a4625884ad') and must exist within the hosting account." } }, "description": "Optional. Cloud networking details, per region. Required if creating an Active-Active subscription." }, + "SubscriptionResourceTagsUpdateRequest": { + "required": [ + "resourceTags" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "resourceTags": { + "type": "array", + "description": "List of resource tags to apply to the subscription. This will replace all existing tags.", + "items": { + "$ref": "#/components/schemas/ResourceTag" + } + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Resource tags update request" + }, "DatabaseTagsUpdateRequest": { "required": [ "tags" @@ -13754,6 +15855,31 @@ }, "description": "Database tags update request message" }, + "PrivateLinkConnectionsDisassociateRequest": { + "required": [ + "connections" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "connections": { + "type": "array", + "description": "List of connections to disassociate from the private link. Each connection must include associationId, type, and principalId.", + "items": { + "$ref": "#/components/schemas/PrivateLinkConnectionDisassociate" + } + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Private Link connections disassociate request" + }, "AccountUsers": { "type": "object", "properties": { @@ -13783,6 +15909,34 @@ ] } }, + "FixedDatabaseUpgradeRedisVersionRequest": { + "required": [ + "targetRedisVersion" + ], + "type": "object", + "properties": { + "databaseId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "targetRedisVersion": { + "type": "string", + "description": "The target Redis version the database will be upgraded to. Use GET /subscriptions/redis-versions to get a list of available Redis versions.", + "example": "7.4" + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Upgrades the specified Essentials database to a later Redis version." + }, "CrdbUpdatePropertiesRequest": { "type": "object", "properties": { @@ -13819,7 +15973,7 @@ "minimum": 0.1, "exclusiveMinimum": false, "type": "number", - "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb.If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.", + "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If \u2018replication\u2019 is 'true', the database\u2019s total memory will be twice as large as the datasetSizeInGb.If \u2018replication\u2019 is false, the database\u2019s total memory will be the datasetSizeInGb value.", "format": "double", "example": 1 }, @@ -13864,6 +16018,10 @@ "type": "string", "description": "Optional. Changes the password used to access the database in all regions that don't set a local 'password'." }, + "globalEnableDefaultUser": { + "type": "boolean", + "description": "Optional. When 'true', allows connecting to the database with the 'default' user in all regions that don't set local 'enableDefaultUser'. When 'false', only defined access control users can connect to the database." + }, "globalSourceIp": { "type": "array", "description": "Optional. List of source IP addresses or subnet masks to whitelist in all regions that don't set local 'sourceIp' settings. If set, Redis clients will be able to connect to this database only from within the specified source IP addresses ranges. Example: ['192.168.10.0/32', '192.168.12.0/24']", @@ -13900,6 +16058,10 @@ "noeviction" ] }, + "autoMinorVersionUpgrade": { + "type": "boolean", + "description": "Optional. Automatically upgrades the database to newer minor versions within the same major release. Applies to version 8.4 and above." + }, "commandType": { "type": "string", "readOnly": true @@ -13921,7 +16083,8 @@ }, "redisRule": { "type": "string", - "description": "Redis ACL rule pattern. See [ACL syntax](https://redis.io/docs/latest/operate/rc/security/access-control/data-access-control/configure-acls/#define-permissions-with-acl-syntax) to learn how to define rules." + "description": "Redis ACL rule pattern. See [ACL syntax](https://redis.io/docs/latest/operate/rc/security/access-control/data-access-control/configure-acls/#define-permissions-with-acl-syntax) to learn how to define rules.", + "example": "+set allkeys allchannels" }, "commandType": { "type": "string", @@ -13961,10 +16124,10 @@ }, "preferredAvailabilityZones": { "type": "array", - "description": "Optional. List the zone ID(s) for your preferred availability zone(s) for the cloud provider and region. If ‘multipleAvailabilityZones’ is set to 'true', you must list three availability zones. Otherwise, list one availability zone.", + "description": "Optional. List the zone ID(s) for your preferred availability zone(s) for the cloud provider and region. If \u2018multipleAvailabilityZones\u2019 is set to 'true', you must list three availability zones. Otherwise, list one availability zone.", "items": { "type": "string", - "description": "Optional. List the zone ID(s) for your preferred availability zone(s) for the cloud provider and region. If ‘multipleAvailabilityZones’ is set to 'true', you must list three availability zones. Otherwise, list one availability zone." + "description": "Optional. List the zone ID(s) for your preferred availability zone(s) for the cloud provider and region. If \u2018multipleAvailabilityZones\u2019 is set to 'true', you must list three availability zones. Otherwise, list one availability zone." } }, "networking": { @@ -14048,7 +16211,7 @@ "minimum": 0.1, "exclusiveMinimum": false, "type": "number", - "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If ‘replication’ is 'true', the database’s total memory will be twice as large as the datasetSizeInGb. If ‘replication’ is false, the database’s total memory will be the datasetSizeInGb value.", + "description": "Optional. The maximum amount of data in the dataset for this database in GB. You cannot set both datasetSizeInGb and totalMemoryInGb. If \u2018replication\u2019 is 'true', the database\u2019s total memory will be twice as large as the datasetSizeInGb. If \u2018replication\u2019 is false, the database\u2019s total memory will be the datasetSizeInGb value.", "format": "double", "example": 1 }, @@ -14057,6 +16220,10 @@ "description": "Optional. If specified, redisVersion defines the Redis database version. If omitted, the Redis version will be set to the default version (available in 'GET /subscriptions/redis-versions')", "example": "7.2" }, + "autoMinorVersionUpgrade": { + "type": "boolean", + "description": "Optional. Automatically upgrades the database to newer minor versions within the same major release. Applies to version 8.4 and above. Default: true." + }, "respVersion": { "type": "string", "description": "Optional. Redis Serialization Protocol version. Must be compatible with Redis version.", @@ -14130,8 +16297,15 @@ }, "averageItemSizeInBytes": { "type": "integer", - "description": "Optional. Relevant only to ram-and-flash (also known as Auto Tiering) subscriptions. Estimated average size in bytes of the items stored in the database. Default: 1000", - "format": "int64" + "description": "Optional. Relevant only to ram-and-flash (also known as Redis-Flex/Auto-Tiering) subscriptions. Estimated average size in bytes of the items stored in the database. Default: 1000", + "format": "int64", + "deprecated": true + }, + "ramPercentage": { + "type": "integer", + "description": "Optional. Relevant only to ram-and-flash (also known as Redis-Flex/Auto-Tiering) subscriptions. The percentage of data to be stored in RAM. Must be between 10 and 50 in steps of 10 (10, 20, 30, 40, 50). Default: 20", + "format": "int32", + "example": 20 }, "periodicBackupPath": { "type": "string", @@ -14187,7 +16361,7 @@ }, "modules": { "type": "array", - "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities.", + "description": "Optional. Redis advanced capabilities (also known as modules) to be provisioned in the database. Use GET /database-modules to get a list of available advanced capabilities. Don't specify modules for database versions 8 and above. All capabilities are bundled in the database by default.", "items": { "$ref": "#/components/schemas/DatabaseModuleSpec" } @@ -14216,6 +16390,10 @@ "Region": { "type": "object", "properties": { + "id": { + "type": "integer", + "format": "int32" + }, "name": { "type": "string" }, @@ -14251,12 +16429,12 @@ "role": { "type": "string", "description": "Optional. Changes the ACL role assigned to the user. Use GET '/acl/roles' to get a list of database access roles.", - "example": "Redis-role-example" + "example": "ACL-role-example" }, "password": { "type": "string", "description": "Optional. Changes the user's database password.", - "example": "some-random-password" + "example": "ab123AB$%^" }, "commandType": { "type": "string", @@ -14265,6 +16443,37 @@ }, "description": "ACL user update request" }, + "PrivateLinkConnectionDisassociate": { + "required": [ + "associationId", + "principalId", + "type" + ], + "type": "object", + "properties": { + "associationId": { + "type": "string", + "description": "Resource share association ID", + "example": "rsa-12345678" + }, + "connectionId": { + "type": "string", + "description": "VPC endpoint connection ID", + "example": "vpce-con-12345678" + }, + "type": { + "type": "string", + "description": "Type of the connection", + "example": "vpc_endpoint" + }, + "principalId": { + "type": "string", + "description": "Principal ID that owns the connection, e.g. AWS account ID", + "example": "123456789012" + } + }, + "description": "Private link connection information for disassociation request" + }, "ProcessorResponse": { "type": "object", "properties": { @@ -14300,21 +16509,21 @@ "SUBSCRIPTION_IN_USE", "SUBSCRIPTION_CA_PROVIDER_MISMATCH", "SUBSCRIPTION_NETWORKING_MISSING", - "SUBSCRIPTION_NETWORKING_CIDR_MISSING", + "NETWORKING_CIDR_MISSING", "SUBSCRIPTION_INVALID_CIDR", - "SUBSCRIPTION_NETWORKING_SECURITY_GROUP_MISSING", - "SUBSCRIPTION_NETWORKING_SUBNET_IDS_MISSING", - "SUBSCRIPTION_NETWORKING_VPC_ID_MISSING", - "SUBSCRIPTION_NETWORKING_CIDR_IS_NOT_SUPPORTED", - "SUBSCRIPTION_NETWORKING_VPC_WITH_SUBNETS_AND_SECURITY_GROUP_IS_NOT_SUPPORTED", - "SUBSCRIPTION_INVALID_NUMBER_OF_SUBNET_IDS", + "NETWORKING_SECURITY_GROUP_MISSING", + "NETWORKING_SUBNET_IDS_MISSING", + "NETWORKING_VPC_ID_MISSING", + "NETWORKING_CIDR_IS_NOT_SUPPORTED", + "NETWORKING_VPC_WITH_SUBNETS_AND_SECURITY_GROUP_IS_NOT_SUPPORTED", + "NETWORKING_VPC_WITH_SUBNETS_AND_SECURITY_GROUP_IS_NOT_SUPPORTED_FOR_INTERNAL_CLOUD_ACCOUNT", + "INVALID_NUMBER_OF_SUBNET_IDS", "SUBSCRIPTION_PI_NOT_FOUND", "SUBSCRIPTION_INVALID_REGION_NAME", "SUBSCRIPTION_INVALID_REGION_ID", "SUBSCRIPTION_BAD_PREFERRED_AZ_SIZE", "SUBSCRIPTION_PREFERRED_AZ_INVALID_VALUE", "SUBSCRIPTION_PREFERRED_AZ_MUST_BE_DEFINED_ONCE", - "ACTIVE_ACTIVE_SUBSCRIPTION_PREFERRED_AZ_NOT_SUPPORTED", "SUBSCRIPTION_PREFERRED_AZ_IS_DISABLED", "SUBSCRIPTION_MUST_HAVE_AT_LEAST_ONE_DATABASE", "SUBSCRIPTION_REDIS_VERSION_INVALID_VALUE", @@ -14323,6 +16532,15 @@ "SUBSCRIPTION_GCP_ALLOW_ONLY_INTERNAL", "CLUSTER_UNDER_MAINTENANCE", "ACTIVE_ACTIVE_SUBSCRIPTION_IS_NOT_SUPPORTED", + "RESOURCE_TAGS_EXCEEDS_MAXIMUM_COUNT", + "RESOURCE_TAG_KEY_EXCEEDS_MAXIMUM_LENGTH", + "RESOURCE_TAG_VALUE_EXCEEDS_MAXIMUM_LENGTH", + "RESOURCE_TAGS_NOT_ALLOWED_WITH_INTERNAL_CLOUD_ACCOUNT", + "RESOURCE_TAGS_NOT_ALLOWED", + "RESOURCE_TAGS_NAME_NOT_ALLOWED", + "RESOURCE_TAGS_EMPTY_KEY", + "RESOURCE_TAGS_DUPLICATE_KEY", + "RESOURCE_TAGS_MISSING_VALUE", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_IS_NOT_SUPPORTED", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_MISSING_USAGE_PERMISSIONS", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_MISSING_GET_KEY_PERMISSIONS", @@ -14330,7 +16548,10 @@ "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_DISABLED_KEY", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_INVALID_KEY_NAME", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_WRONG_REGION", - "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_NOT_PENDING", + "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_NOT_ALLOWED_WITH_CLOUD_PROVIDER_MANAGED_KEY", + "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_NOT_ALLOWED_WITH_INTERNAL_CLOUD_ACCOUNT", + "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_REQUIRED_FOR_EXTERNAL_CLOUD_ACCOUNT", + "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_DELETION_GRACE_PERIOD_REQUIRED", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_INVALID_NUMBER_OF_KEYS", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_REGION_NOT_REQUIRED", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_REGION_REQUIRED", @@ -14338,7 +16559,8 @@ "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_INVALID_REGION", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_DUPLICATE_REGIONS", "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_INVALID_FORMAT", - "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_CREATE_FAILED", + "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_UPDATE_IS_NOT_SUPPORTED", + "CUSTOMER_MANAGED_PERSISTENT_STORAGE_ENCRYPTION_KEY_SUBSCRIPTION_INVALID_STATUS", "ACTIVE_ACTIVE_CREATE_A_REGION_CUSTOMER_MANAGED_KEY_RESOURCE_NAME_SUBSCRIPTION_IS_NOT_CUSTOMER_MANAGED", "ACTIVE_ACTIVE_CREATE_A_REGION_CUSTOMER_MANAGED_KEY_RESOURCE_NAME_IS_NOT_SET", "PLANNED_SUBSCRIPTION_INVALID_PLAN_ID", @@ -14371,11 +16593,8 @@ "DATABASE_QUERY_PERFORMANCE_FACTOR_IS_NOT_SUPPORTED_ON_ACTIVE_ACTIVE", "REDISEARCH_SUPPORTS_ONLY_OPERATIONS_PER_SECOND_AS_THROUGHPUT_MEASUREMENT", "REDIS_GRAPH_SUPPORTS_ONLY_OPS_PER_SECOND_AS_THROUGHPUT_MEASUREMENT", - "DATABASE_MULTI_MODULES_IS_DISABLED", "DATABASE_RESP_VERSION_IS_NOT_SUPPORTED", "DATABASE_RESP_VERSION_IS_NOT_SUPPORTED_ON_CREATE_SUBSCRIPTION", - "CLUSTER_MULTI_MODULES_IS_NOT_SUPPORTED", - "DATABASE_INVALID_MULTI_MODULES_COMBINATION", "DATABASE_ROF_NOT_SUPPORTED", "DATABASE_REDISGRAPH_OVERSIZED", "DATABASE_BACKUP_NOT_SUPPORTED", @@ -14403,6 +16622,7 @@ "DATABASE_MODULE_MUST_BE_DEFINED_ONCE", "DATABASE_MEMCACHED_CONTAINS_MODULES", "DATABASE_MEMCACHED_NOT_SUPPORT_OSS_CLUSTER_API", + "REDIS_ON_FLASH_DATABASE_MEMCACHED_PROTOCOL_IS_NOT_ALLOWED", "DATABASE_MEMCACHED_CONTAINS_REDIS_PASSWORD", "DATABASE_MEMCACHED_CONTAINS_REDIS_DEFAULT_USER", "DATABASE_MEMCACHED_SASL_USERNAME_IS_BLANK", @@ -14410,6 +16630,12 @@ "DATABASE_MEMCACHED_SASL_PASSWORD_MAX_LENGTH", "DATABASE_REDIS_FLEX_CONTAINS_MODULES", "DATABASE_AVERAGE_ITEM_SIZE_NOT_ALLOWED", + "DATABASE_RAM_PERCENTAGE_NOT_ALLOWED", + "DATABASE_RAM_PERCENTAGE_NOT_SUPPORTED", + "DATABASE_RAM_PERCENTAGE_IS_INVALID", + "DATABASE_AVERAGE_ITEM_SIZE_IS_DEPRECATED", + "DATABASE_MEMORY_LIMIT_IS_INVALID_FOR_ROF", + "DATABASE_DATASET_SIZE_IS_INVALID_FOR_ROF", "DATABASE_SIZE_SMALLER_THAN_USAGE", "DATABASE_USAGE_EXCEEDS_GLOBAL_LIMIT", "DATABASE_USAGE_EXCEEDS_LOCAL_LIMIT", @@ -14420,10 +16646,12 @@ "DATABASE_CLIENT_SSL_CERTIFICATE_MORE_THAN_1_ACTIVE", "DATABASE_SIP_OVER_LIMIT", "DATABASE_INVALID_SIP", + "DATABASE_INVALID_SIP_FREE_PLAN", "DATABASE_INVALID_ALERTS", "DATABASE_INVALID_MODULE", "DATABASE_INVALID_MODULE_PARAMETER", "DATABASE_INVALID_MODULE_PARAMETER_VALUE", + "DATABASE_EXPLICIT_MODULES_NOT_SUPPORTED_FOR_THIS_REDIS_VERSION", "DATABASE_INVALID_ALERT_VALUE", "DATABASE_SHARDING_TYPE_IS_IMMUTABLE", "DATABASE_SHARDING_TYPE_IS_NOT_SUPPORTED", @@ -14455,6 +16683,7 @@ "DATABASE_INVALID_REGEX_RULES", "DATABASE_INVALID_QUANTITY", "DATABASE_REPLICA_OF_VERSION_NOT_COMPATIBLE", + "DATABASE_REPLICA_OF_SOURCE_INCOMPATIBLE", "DATABASE_IMPORT_FAILED", "DATABASE_IMPORT_FROM_NON_OSS", "DATABASE_IMPORT_SOURCE_NOT_FOUND", @@ -14464,6 +16693,7 @@ "DATABASE_IMPORT_MULTIPLE_REDIS_SOURCES", "DATABASE_IMPORT_REDIS_BAD_URI", "DATABASE_REPLICA_OF_BAD_URI", + "DATABASE_REPLICA_OF_DYNAMIC_ENDPOINT_NOT_ALLOWED", "DATABASE_IMPORT_S3_BAD_URI", "DATABASE_IMPORT_HTTP_BAD_URI", "DATABASE_IMPORT_FTP_BAD_URI", @@ -14473,11 +16703,16 @@ "DATABASE_PORT_INVALID_VALUE", "DATABASE_PORT_IS_UNAVAILABLE", "DATABASE_CUSTOM_PORT_NOT_SUPPORTED", + "DATABASE_CUSTOM_PORT_NOT_UNIQUE", "DATABASE_AVERAGE_ITEM_SIZE_INVALID_VALUE", "DATABASE_REDIS_VERSION_IS_NOT_SUPPORTED", + "DATABASE_REDIS_VERSION_IS_NOT_SUPPORTED_FOR_REGION", "DATABASE_REDIS_VERSION_IS_NOT_SUPPORTED_FOR_MEMCACHED", "DATABASE_REDIS_VERSION_IS_REQUIRED", "DATABASE_REDIS_VERSION_INVALID_VALUE", + "INCOMPATIBLE_TF_PROVIDER", + "DESIRED_SOFTWARE_VERSION_IS_NOT_SUPPORTED", + "CONNECTIVITY_REQUESTS_ON_CUSTOMER_MANAGED_VPC_SUBSCRIPTION", "VPC_PEERING_NOT_ACTIVE", "VPC_PEERING_GENERAL_ERROR", "VPC_PEERING_INVALID_ACCOUNT", @@ -14560,6 +16795,10 @@ "CIDR_WHITELIST_DUPLICATE_CIDRS", "CIDR_WHITELIST_DUPLICATE_SG", "CIDR_WHITELIST_NOT_ALLOWED", + "CLIENT_PUBLIC_ACCESS_INVALID_SOURCE_IPS", + "CLIENT_PUBLIC_ACCESS_NOT_SUPPORTED", + "CLIENT_PUBLIC_ACCESS_ALREADY_SET", + "CLIENT_PUBLIC_ACCESS_ON_NON_HOSTED", "AWS_ERROR_INSTANCE_LIMIT_EXCEEDED", "AWS_ERROR_VPC_LIMIT_EXCEEDED", "AWS_ERROR_INSUFFICIENT_INSTANCE_CAPACITY", @@ -14573,6 +16812,7 @@ "PAYMENT_INFO_NOT_ALLOWED_IN_GCP_ACCOUNT", "CLOUD_PROVIDER_IS_NOT_GCP_IN_GCP_ACCOUNT", "PAYMENT_INFO_NOT_ALLOWED_IN_CONTRACT_ASSOCIATED_ACCOUNT", + "PAYMENT_INFO_CHANGE_PROHIBITED_FOR_PRO_UNDER_CONTRACT", "LOCAL_THROUGHPUT_READ_AND_WRITE_OPERATIONS_PER_SECOND_VALUES_MUST_BE_IN_INCREMENTS_OF_500_OR_MINIMUM", "MISSING_REGIONS_BETWEEN_CLOUD_PROVIDERS_AND_DATABASES_LOCAL_THROUGHPUT_MEASUREMENTS", "MISSING_REGIONS_BETWEEN_LOCAL_THROUGHPUT_MEASUREMENTS_AND_SUBSCRIPTION_REGIONS", @@ -14693,6 +16933,7 @@ "PAYMENT_INVALID_CARD_TYPE", "PAYMENT_CVV_MISSING", "PAYMENT_GENERAL_ERROR", + "PAYMENT_HOLD_FAILED", "ACL_USER_NAME_ALREADY_EXISTS", "ACL_USER_NAME_NOT_VALID", "ACL_USER_NOT_FOUND", @@ -14817,7 +17058,37 @@ "ACTIVE_ACTIVE_GCP_EXTERNAL_CLOUD_ACCOUNT_NOT_SUPPORTED", "DEDICATED_SUBSCRIPTION_PREFERRED_AZ_INVALID_VALUE", "DEDICATED_SUBSCRIPTION_INVALID_INSTANCE_NAME", - "DEDICATED_SUBSCRIPTION_INVALID_REPLICATION" + "DEDICATED_SUBSCRIPTION_INVALID_REPLICATION", + "PRIVATE_LINK_NOT_FOUND", + "PRIVATE_LINK_ALREADY_EXISTS", + "PRIVATE_LINK_PRINCIPAL_ALREADY_EXISTS", + "PRIVATE_LINK_PRINCIPAL_NOT_FOUND", + "PRIVATE_LINK_PRINCIPAL_INVALID_PRINCIPLE", + "PRIVATE_LINK_CLOUD_PROVIDER_NOT_SUPPORTED", + "PRIVATE_LINK_GET_A_FLEXIBLE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_AN_ACTIVE_ACTIVE_SUBSCRIPTION", + "PRIVATE_LINK_GET_AN_ACTIVE_ACTIVE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_A_SINGLE_REGION_SUBSCRIPTION", + "PRIVATE_LINK_CREATING_PRINCIPLES_IS_NOT_ALLOWED_WITH_AN_ACTIVE_ACTIVE_SUBSCRIPTION", + "PRIVATE_LINK_CREATING_PRINCIPLES_IS_NOT_ALLOWED_WITH_A_SINGLE_REGION_SUBSCRIPTION", + "PRIVATE_LINK_DELETING_A_FLEXIBLE_SUBSCRIPTION_PRINCIPALS_IS_NOT_ALLOWED_WITH_AN_ACTIVE_ACTIVE_SUBSCRIPTION", + "PRIVATE_LINK_DELETING_AN_ACTIVE_ACTIVE_SUBSCRIPTION_PRINCIPALS_IS_NOT_ALLOWED_WITH_A_SINGLE_REGION_SUBSCRIPTION", + "PRIVATE_LINK_CREATE_A_FLEXIBLE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_AN_ACTIVE_ACTIVE_SUBSCRIPTION", + "PRIVATE_LINK_CREATE_AN_ACTIVE_ACTIVE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_A_SINGLE_REGION_SUBSCRIPTION", + "PRIVATE_LINK_DELETING_A_FLEXIBLE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_AN_ACTIVE_ACTIVE_SUBSCRIPTION", + "PRIVATE_LINK_DELETING_AN_ACTIVE_ACTIVE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_A_SINGLE_REGION_SUBSCRIPTION", + "PRIVATE_LINK_IS_NOT_SUPPORTED", + "PRIVATE_LINK_SERVICE_ERROR", + "PRIVATE_LINK_ALL_PRINCIPALS_MUST_BE_DELETED_BEFORE_DELETING_RESOURCE_LINK", + "PRIVATE_LINK_DISASSOCIATE_CONNECTIONS_A_FLEXIBLE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_AN_ACTIVE_ACTIVE_SUBSCRIPTION", + "PRIVATE_LINK_DISASSOCIATE_CONNECTIONS_AN_ACTIVE_ACTIVE_SUBSCRIPTION_PRIVATE_LINK_IS_NOT_ALLOWED_WITH_A_SINGLE_REGION_SUBSCRIPTION", + "COST_REPORT_IS_NOT_SUPPORTED", + "COST_REPORT_START_DATE_IS_MISSING", + "COST_REPORT_END_DATE_IS_MISSING", + "COST_REPORT_INVALID_DATE_FORMAT", + "COST_REPORT_END_DATE_BEFORE_START_DATE", + "COST_REPORT_DATE_RANGE_EXCEEDS_LIMIT", + "COST_REPORT_TAG_KEY_EMPTY", + "COST_REPORT_TAG_VALUE_EMPTY", + "COST_REPORT_FUTURE_DATES_NOT_ALLOWED" ] }, "additionalInfo": { @@ -14833,7 +17104,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } }, @@ -14943,6 +17214,20 @@ }, "description": "Database backup request message" }, + "ReplicaAsSourceEndpoints": { + "type": "object", + "properties": { + "public": { + "type": "string", + "description": "Public cluster endpoint that can be used as source for replication" + }, + "private": { + "type": "string", + "description": "Private cluster endpoint that can be used as source for replication" + } + }, + "description": "Endpoints to use when configuring another database to replicate from this database (Make sure to use this instead of the dynamic endpoints)." + }, "DataPersistenceOptions": { "type": "object", "properties": { @@ -14957,7 +17242,7 @@ "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -15232,7 +17517,7 @@ }, "paymentMethod": { "type": "string", - "description": "Optional. The payment method for the subscription. If set to ‘credit-card’, ‘paymentMethodId’ must be defined. Default: 'credit-card'", + "description": "Optional. The payment method for the subscription. If set to \u2018credit-card\u2019, \u2018paymentMethodId\u2019 must be defined. Default: 'credit-card'", "enum": [ "credit-card", "marketplace" @@ -15240,7 +17525,7 @@ }, "paymentMethodId": { "type": "integer", - "description": "Optional. A valid payment method ID for this account. Use GET /payment-methods to get a list of all payment methods for your account. This value is optional if ‘paymentMethod’ is ‘marketplace’, but required for all other account types.", + "description": "Optional. A valid payment method ID for this account. Use GET /payment-methods to get a list of all payment methods for your account. This value is optional if \u2018paymentMethod\u2019 is \u2018marketplace\u2019, but required for all other account types.", "format": "int32" }, "memoryStorage": { @@ -15254,13 +17539,16 @@ }, "persistentStorageEncryptionType": { "type": "string", - "description": "Optional. Persistent storage encryption secures data-at-rest for database persistence. You can use 'cloud-provider-managed-key' or 'customer-managed-key'. Default: 'cloud-provider-managed-key'", + "description": "Optional. Persistent storage encryption secures data at rest for database persistence. By default, disk storage is encrypted by keys managed by the cloud provider. Use 'customer-managed-key' if you want to use self-managed persistent storage encryption keys. Default: 'cloud-provider-managed-key'", "example": "cloud-provider-managed-key", "enum": [ "cloud-provider-managed-key", "customer-managed-key" ] }, + "persistentStorageEncryptionKeys": { + "$ref": "#/components/schemas/CustomerManagedKeyProperties" + }, "cloudProviders": { "type": "array", "description": "Cloud provider, region, and networking details.", @@ -15281,6 +17569,10 @@ "example": "7.2", "deprecated": true }, + "publicEndpointAccess": { + "type": "boolean", + "description": "Optional. When 'false', all databases on this subscription will reject any connection attempt to the public endpoint and any connection attempt to the private endpoint that does not come from an IP address in the private address space defined in [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918#section-3 ). You must use a [private connectivity method](https://redis.io/docs/latest/operate/rc/security/database-security/block-public-endpoints/#private-connectivity-methods ) to connect to a database with a blocked public endpoint. Default: 'true'." + }, "commandType": { "type": "string", "readOnly": true @@ -15350,6 +17642,56 @@ }, "description": "Cloud Account definition" }, + "PrivateLinkCreateRequest": { + "required": [ + "principal", + "shareName", + "type" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "shareName": { + "maxLength": 64, + "minLength": 0, + "type": "string", + "description": "Name of the resource share", + "example": "my-redis-share" + }, + "principal": { + "type": "string", + "description": "AWS account ID or ARN of the principal (IAM user, role, or account)", + "example": "123456789012" + }, + "type": { + "type": "string", + "description": "Type of the principal", + "example": "aws_account", + "enum": [ + "aws_account", + "organization", + "organization_unit", + "iam_role", + "iam_user", + "service_principal" + ] + }, + "alias": { + "type": "string", + "description": "Alias or friendly name for the principal", + "example": "Production Account" + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Private Link create request" + }, "SubscriptionPricings": { "type": "object", "properties": { @@ -15408,6 +17750,36 @@ }, "description": "Optional. Changes Replica Of (also known as Active-Passive) configuration details." }, + "PrivateLinkActiveActivePrincipalsDeleteRequest": { + "required": [ + "principal", + "regionId" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "regionId": { + "type": "integer", + "description": "Deployment region id as defined by cloud provider", + "format": "int32", + "readOnly": true + }, + "principal": { + "type": "string", + "description": "An AWS account ID or ARN to remove from the private link", + "example": "123456789012" + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Request to remove principals from private link for Active-Active subscription" + }, "DatabaseThroughputSpec": { "required": [ "by", @@ -15560,12 +17932,15 @@ "dynamicEndpoints": { "$ref": "#/components/schemas/DynamicEndpoints" }, + "replicaAsSourceEndpoints": { + "$ref": "#/components/schemas/ReplicaAsSourceEndpoints" + }, "links": { "type": "array", "items": { "type": "object", "additionalProperties": { - "type": "object" + "type": "string" } } } @@ -15734,20 +18109,17 @@ "properties": { "resourceName": { "type": "string", - "description": "Required. Resource name of the customer managed key as defined by the cloud provider.", + "description": "The resource name of the customer managed key.", "example": "projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME" }, "region": { "type": "string", - "description": "Name of region to for the customer managed key as defined by the cloud provider. Required for active-active subscriptions." + "description": "(Required for Active-Active subscriptions only) Region for the customer managed key as defined by the cloud provider." } }, "description": "Object representing a customer managed key (CMK), along with the region it is associated to." }, "ActiveActiveRegionCreateRequest": { - "required": [ - "deploymentCIDR" - ], "type": "object", "properties": { "subscriptionId": { @@ -15769,6 +18141,29 @@ "description": "Deployment CIDR mask. Must be a valid CIDR format with a range of 256 IP addresses.", "example": "10.0.0.0/24" }, + "subnetIds": { + "type": "array", + "description": "Optional. Enter a list of subnets identifiers that exists in the hosted AWS account. Subnet Identifier must exist within the hosting account.", + "example": "['subnet-0125be68a4625884ad', 'subnet-0125be68a4625884ad','subnet-0125be68a4625884ad']", + "items": { + "type": "string", + "description": "Optional. Enter a list of subnets identifiers that exists in the hosted AWS account. Subnet Identifier must exist within the hosting account.", + "example": "['subnet-0125be68a4625884ad', 'subnet-0125be68a4625884ad','subnet-0125be68a4625884ad']" + } + }, + "securityGroupId": { + "type": "string", + "description": "Optional. Enter a security group identifier that exists in the hosted AWS account. Security group Identifier must be in a valid format (for example: 'sg-0125be68a4625884ad') and must exist within the hosting account.", + "example": "sg-0125be68a4625884ad" + }, + "preferredAvailabilityZones": { + "type": "array", + "description": "Optional. List the zone IDs for your preferred availability zones for the cloud provider and region.", + "items": { + "type": "string", + "description": "Optional. List the zone IDs for your preferred availability zones for the cloud provider and region." + } + }, "dryRun": { "type": "boolean", "description": "Optional. When 'false': Creates a deployment plan and deploys it, creating any resources required by the plan. When 'true': creates a read-only deployment plan, and does not create any resources. Default: 'false'", @@ -15793,7 +18188,7 @@ }, "customerManagedKeyResourceName": { "type": "string", - "description": "Optional. Resource name of the customer managed key as defined by the cloud provider for customer managed subscriptions.", + "description": "Required for subscriptions where 'persistentStorageEncryptionType' is 'customer-managed-key'. The resource name of the customer-managed encryption key for the region.", "example": "projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY_NAME" }, "commandType": { @@ -15848,6 +18243,61 @@ }, "description": "Database import request" }, + "PrivateLinkPrincipalsDeleteRequest": { + "required": [ + "principal" + ], + "type": "object", + "properties": { + "subscriptionId": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "principal": { + "type": "string", + "description": "An AWS account ID or ARN to remove from the private link", + "example": "123456789012" + }, + "commandType": { + "type": "string", + "readOnly": true + } + }, + "description": "Private Link principals delete request" + }, + "CustomerManagedKeyProperties": { + "required": [ + "customerManagedKeys" + ], + "type": "object", + "properties": { + "customerManagedKeys": { + "type": "array", + "description": "The customer managed keys (CMK) to use for this subscription. If is active-active subscription, must set a key for each region.", + "items": { + "$ref": "#/components/schemas/CustomerManagedKey" + } + }, + "deletionGracePeriod": { + "type": "string", + "description": "Optional. The grace period for deleting the subscription if Redis cannot access the provided key. Required when applying customer managed keys for a new subscription.", + "example": "alerts-only", + "enum": [ + "alerts-only", + "immediate", + "15-minutes", + "30-minutes", + "1-hour", + "4-hours", + "8-hours", + "12-hours", + "24-hours" + ] + } + }, + "description": "Optional. Contains information about the keys used for each region. Can be used only with external cloud account" + }, "VpcPeeringCreateBaseRequest": { "type": "object", "properties": { @@ -15880,6 +18330,11 @@ "type": "apiKey", "name": "x-api-secret-key", "in": "header" + }, + "x-auth-token": { + "type": "apiKey", + "name": "x-auth-token", + "in": "header" } } } diff --git a/tests/fixtures/openapi_non_spec_routes.txt b/tests/fixtures/openapi_non_spec_routes.txt new file mode 100644 index 0000000..f8cd777 --- /dev/null +++ b/tests/fixtures/openapi_non_spec_routes.txt @@ -0,0 +1,2 @@ +# Typed handler routes that do not match the current bundled OpenAPI spec. +# Keep entries normalized as: METHOD /path/{}/segments diff --git a/tests/fixtures/openapi_unsupported_routes.txt b/tests/fixtures/openapi_unsupported_routes.txt new file mode 100644 index 0000000..df38bae --- /dev/null +++ b/tests/fixtures/openapi_unsupported_routes.txt @@ -0,0 +1,2 @@ +# Bundled-spec routes that do not currently have a matching typed handler path. +# Keep entries normalized as: METHOD /path/{}/segments diff --git a/tests/openapi_route_coverage.rs b/tests/openapi_route_coverage.rs new file mode 100644 index 0000000..c072f1d --- /dev/null +++ b/tests/openapi_route_coverage.rs @@ -0,0 +1,203 @@ +//! Route coverage checks against the bundled OpenAPI spec. +//! +//! These tests compare normalized path templates extracted from the typed +//! handler implementation with the vendored OpenAPI fixture. Any gap between +//! the two must be tracked explicitly in an allowlist file so coverage drift +//! is visible in review. + +use regex::Regex; +use serde_json::Value; +use std::collections::BTreeSet; +use std::fs; +use std::path::{Path, PathBuf}; + +const OPENAPI_SPEC: &str = include_str!("fixtures/cloud_openapi.json"); +const UNSUPPORTED_SPEC_ROUTES: &str = include_str!("fixtures/openapi_unsupported_routes.txt"); +const NON_SPEC_HANDLER_ROUTES: &str = include_str!("fixtures/openapi_non_spec_routes.txt"); + +fn normalize_path(path: &str) -> String { + let path = path.replace("{query_string}", ""); + let path = path.split('?').next().unwrap_or(&path); + let params = Regex::new(r"\{[^}]+\}").expect("valid path parameter regex"); + let normalized = params.replace_all(path, "{}"); + let normalized = normalized.trim_end_matches('/'); + + if normalized.is_empty() { + "/".to_string() + } else { + normalized.to_string() + } +} + +fn spec_routes() -> BTreeSet { + let spec: Value = serde_json::from_str(OPENAPI_SPEC).expect("valid bundled OpenAPI spec"); + let mut routes = BTreeSet::new(); + + for (path, methods) in spec["paths"] + .as_object() + .expect("OpenAPI paths should be an object") + { + for method in methods + .as_object() + .expect("OpenAPI path methods should be an object") + .keys() + { + let upper = method.to_ascii_uppercase(); + if matches!(upper.as_str(), "GET" | "POST" | "PUT" | "DELETE" | "PATCH") { + routes.insert(format!("{upper} {}", normalize_path(path))); + } + } + } + + routes +} + +fn load_route_list(contents: &str) -> BTreeSet { + contents + .lines() + .map(str::trim) + .filter(|line| !line.is_empty() && !line.starts_with('#')) + .map(ToOwned::to_owned) + .collect() +} + +fn source_files(dir: &Path) -> Vec { + let mut files = Vec::new(); + + for entry in fs::read_dir(dir).expect("source directory should be readable") { + let entry = entry.expect("directory entry should be readable"); + let path = entry.path(); + + if path.is_dir() { + if path.file_name().and_then(|s| s.to_str()) == Some("testing") { + continue; + } + + files.extend(source_files(&path)); + continue; + } + + if path.extension().and_then(|s| s.to_str()) != Some("rs") { + continue; + } + + let skip = matches!( + path.file_name().and_then(|s| s.to_str()), + Some("client.rs" | "lib.rs" | "lib_tests.rs") + ); + + if !skip { + files.push(path); + } + } + + files +} + +fn strip_line_comments(contents: &str) -> String { + contents + .lines() + .filter(|line| !line.trim_start().starts_with("//")) + .collect::>() + .join("\n") +} + +fn extracted_handler_routes() -> BTreeSet { + let direct = Regex::new( + r#"\.(?Pget|get_raw|get_bytes|post|post_raw|put|put_raw|patch_raw|delete|delete_raw|delete_with_body)\(\s*"(?P/[^"\n]*)""#, + ) + .expect("valid direct call regex"); + let formatted = Regex::new( + r#"\.(?Pget|get_raw|get_bytes|post|post_raw|put|put_raw|patch_raw|delete|delete_raw|delete_with_body)\(\s*&?format!\(\s*"(?P/[^"\n]*)""#, + ) + .expect("valid format call regex"); + + let verbs = [ + ("get", "GET"), + ("get_raw", "GET"), + ("get_bytes", "GET"), + ("post", "POST"), + ("post_raw", "POST"), + ("put", "PUT"), + ("put_raw", "PUT"), + ("patch_raw", "PATCH"), + ("delete", "DELETE"), + ("delete_raw", "DELETE"), + ("delete_with_body", "DELETE"), + ]; + + let verb_map = verbs + .into_iter() + .collect::>(); + let mut routes = BTreeSet::new(); + let src_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("src"); + + for file in source_files(&src_dir) { + let contents = fs::read_to_string(&file).expect("source file should be readable"); + let contents = strip_line_comments(&contents); + + for captures in direct.captures_iter(&contents) { + let verb = captures.name("verb").expect("verb capture").as_str(); + let path = captures.name("path").expect("path capture").as_str(); + let method = verb_map[verb]; + routes.insert(format!("{method} {}", normalize_path(path))); + } + + for captures in formatted.captures_iter(&contents) { + let verb = captures.name("verb").expect("verb capture").as_str(); + let path = captures.name("path").expect("path capture").as_str(); + let method = verb_map[verb]; + routes.insert(format!("{method} {}", normalize_path(path))); + } + } + + routes +} + +fn unexpected_entries(set: &BTreeSet, expected: &BTreeSet) -> Vec { + set.difference(expected).cloned().collect() +} + +#[test] +fn test_openapi_spec_routes_are_accounted_for() { + let spec = spec_routes(); + let extracted = extracted_handler_routes(); + let allowlisted = load_route_list(UNSUPPORTED_SPEC_ROUTES); + + let uncovered_spec_routes: BTreeSet<_> = spec.difference(&extracted).cloned().collect(); + let unexpected = unexpected_entries(&uncovered_spec_routes, &allowlisted); + assert!( + unexpected.is_empty(), + "Found spec routes without handler coverage or allowlist entries:\n{}", + unexpected.join("\n") + ); + + let stale_allowlist = unexpected_entries(&allowlisted, &uncovered_spec_routes); + assert!( + stale_allowlist.is_empty(), + "Found stale unsupported-spec route allowlist entries:\n{}", + stale_allowlist.join("\n") + ); +} + +#[test] +fn test_non_spec_handler_routes_are_explicitly_allowlisted() { + let spec = spec_routes(); + let extracted = extracted_handler_routes(); + let allowlisted = load_route_list(NON_SPEC_HANDLER_ROUTES); + + let non_spec_routes: BTreeSet<_> = extracted.difference(&spec).cloned().collect(); + let unexpected = unexpected_entries(&non_spec_routes, &allowlisted); + assert!( + unexpected.is_empty(), + "Found handler routes that do not exist in the bundled OpenAPI spec:\n{}", + unexpected.join("\n") + ); + + let stale_allowlist = unexpected_entries(&allowlisted, &non_spec_routes); + assert!( + stale_allowlist.is_empty(), + "Found stale non-spec handler route allowlist entries:\n{}", + stale_allowlist.join("\n") + ); +} diff --git a/tests/openapi_validation.rs b/tests/openapi_validation.rs index 69a2916..910a1ab 100644 --- a/tests/openapi_validation.rs +++ b/tests/openapi_validation.rs @@ -36,11 +36,12 @@ fn test_all_endpoints_documented() { } } - // The OpenAPI spec in our repo has 130 endpoints - // (Note: The spec we analyzed from redis.io had 140, but this is the version we have) + // The refreshed OpenAPI fixture currently exposes 151 HTTP operations. + // Keep this as a lower bound so small upstream additions do not require + // an immediate test rewrite, while still catching accidental regressions. assert!( - endpoint_count >= 130, - "Expected at least 130 endpoints in OpenAPI spec, found {}", + endpoint_count >= 150, + "Expected at least 150 endpoints in OpenAPI spec, found {}", endpoint_count ); } diff --git a/tests/private_link_tests.rs b/tests/private_link_tests.rs index 0c05ad4..8f8ea18 100644 --- a/tests/private_link_tests.rs +++ b/tests/private_link_tests.rs @@ -1,5 +1,7 @@ use redis_cloud::connectivity::{ - PrincipalType, PrivateLinkAddPrincipalRequest, PrivateLinkCreateRequest, + PrincipalType, PrivateLinkActiveActiveConnectionsDisassociateRequest, + PrivateLinkAddPrincipalRequest, PrivateLinkConnectionDisassociate, + PrivateLinkConnectionsDisassociateRequest, PrivateLinkCreateRequest, PrivateLinkRemovePrincipalRequest, }; use redis_cloud::{CloudClient, PrivateLinkHandler}; @@ -168,6 +170,52 @@ async fn test_remove_principals() { assert_eq!(result["status"], "deleted"); } +#[tokio::test] +async fn test_disassociate_connections() { + let mock_server = MockServer::start().await; + + let response_body = json!({ + "taskId": "task-disassociate-private-link", + "status": "processing" + }); + + Mock::given(method("POST")) + .and(path( + "/subscriptions/123/private-link/connections/disassociate", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(200).set_body_json(&response_body)) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key") + .api_secret("test-secret") + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PrivateLinkHandler::new(client); + let request = PrivateLinkConnectionsDisassociateRequest { + subscription_id: None, + connections: vec![PrivateLinkConnectionDisassociate { + association_id: "rsa-12345678".to_string(), + connection_id: Some("vpce-con-12345678".to_string()), + connection_type: "vpc_endpoint".to_string(), + principal_id: "123456789012".to_string(), + }], + command_type: None, + }; + + let result = handler + .disassociate_connections(123, &request) + .await + .unwrap(); + + assert_eq!(result["taskId"], "task-disassociate-private-link"); +} + #[tokio::test] async fn test_get_endpoint_script() { let mock_server = MockServer::start().await; @@ -401,6 +449,83 @@ async fn test_get_endpoint_script_active_active() { assert!(result["script"].as_str().unwrap().contains("aws ec2")); } +#[tokio::test] +async fn test_delete_active_active_private_link() { + let mock_server = MockServer::start().await; + + let response_body = json!({ + "taskId": "task-delete-aa-private-link", + "status": "processing" + }); + + Mock::given(method("DELETE")) + .and(path("/subscriptions/123/regions/1/private-link")) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(200).set_body_json(&response_body)) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key") + .api_secret("test-secret") + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PrivateLinkHandler::new(client); + let result = handler.delete_active_active(123, 1).await.unwrap(); + + assert_eq!(result["taskId"], "task-delete-aa-private-link"); +} + +#[tokio::test] +async fn test_disassociate_connections_active_active() { + let mock_server = MockServer::start().await; + + let response_body = json!({ + "taskId": "task-disassociate-aa-private-link", + "status": "processing" + }); + + Mock::given(method("POST")) + .and(path( + "/subscriptions/123/regions/1/private-link/connections/disassociate", + )) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(200).set_body_json(&response_body)) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key") + .api_secret("test-secret") + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = PrivateLinkHandler::new(client); + let request = PrivateLinkActiveActiveConnectionsDisassociateRequest { + subscription_id: None, + region_id: None, + connections: vec![PrivateLinkConnectionDisassociate { + association_id: "rsa-87654321".to_string(), + connection_id: Some("vpce-con-87654321".to_string()), + connection_type: "vpc_endpoint".to_string(), + principal_id: "210987654321".to_string(), + }], + command_type: None, + }; + + let result = handler + .disassociate_connections_active_active(123, 1, &request) + .await + .unwrap(); + + assert_eq!(result["taskId"], "task-disassociate-aa-private-link"); +} + #[tokio::test] async fn test_error_handling_401() { let mock_server = MockServer::start().await; diff --git a/tests/subscriptions_tests.rs b/tests/subscriptions_tests.rs index 8d0cd4d..c800a52 100644 --- a/tests/subscriptions_tests.rs +++ b/tests/subscriptions_tests.rs @@ -1,6 +1,6 @@ use redis_cloud::{CloudClient, SubscriptionsHandler}; use serde_json::json; -use wiremock::matchers::{header, method, path, query_param}; +use wiremock::matchers::{body_json, header, method, path, query_param}; use wiremock::{Mock, MockServer, ResponseTemplate}; #[tokio::test] @@ -382,6 +382,68 @@ async fn test_update_subscription_maintenance_windows() { assert_eq!(result.task_id, Some("task-update-maintenance".to_string())); } +#[tokio::test] +async fn test_update_subscription_resource_tags() { + let mock_server = MockServer::start().await; + + Mock::given(method("PUT")) + .and(path("/subscriptions/123/resource-tags")) + .and(body_json(json!({ + "resourceTags": [ + { + "key": "environment", + "value": "production" + }, + { + "key": "team", + "value": "platform" + } + ] + }))) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-update-resource-tags", + "commandType": "UPDATE_RESOURCE_TAGS", + "status": "processing" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = SubscriptionsHandler::new(client); + let request = redis_cloud::subscriptions::SubscriptionResourceTagsUpdateRequest { + subscription_id: None, + resource_tags: vec![ + redis_cloud::subscriptions::ResourceTag { + key: "environment".to_string(), + value: "production".to_string(), + }, + redis_cloud::subscriptions::ResourceTag { + key: "team".to_string(), + value: "platform".to_string(), + }, + ], + command_type: None, + }; + + let result = handler + .update_subscription_resource_tags(123, &request) + .await + .unwrap(); + + assert_eq!( + result.task_id, + Some("task-update-resource-tags".to_string()) + ); +} + #[tokio::test] async fn test_get_subscription_pricing() { let mock_server = MockServer::start().await; @@ -424,8 +486,56 @@ async fn test_get_subscription_pricing() { assert_eq!(pricing[0].r#type, Some("Shards".to_string())); } -// Skipping test_delete_regions_from_active_active_subscription -// as the client doesn't yet support DELETE with body +#[tokio::test] +async fn test_delete_regions_from_active_active_subscription() { + let mock_server = MockServer::start().await; + + Mock::given(method("DELETE")) + .and(path("/subscriptions/123/regions")) + .and(body_json(json!({ + "regions": [ + { + "region": "us-east-1" + } + ], + "dryRun": false + }))) + .and(header("x-api-key", "test-key")) + .and(header("x-api-secret-key", "test-secret")) + .respond_with(ResponseTemplate::new(202).set_body_json(json!({ + "taskId": "task-delete-region", + "commandType": "DELETE_REGION", + "status": "processing" + }))) + .mount(&mock_server) + .await; + + let client = CloudClient::builder() + .api_key("test-key".to_string()) + .api_secret("test-secret".to_string()) + .base_url(mock_server.uri()) + .build() + .unwrap(); + + let handler = SubscriptionsHandler::new(client); + let request = redis_cloud::subscriptions::ActiveActiveRegionDeleteRequest { + subscription_id: None, + regions: Some(vec![ + redis_cloud::subscriptions::ActiveActiveRegionToDelete { + region: Some("us-east-1".to_string()), + }, + ]), + dry_run: Some(false), + command_type: None, + }; + + let result = handler + .delete_regions_from_active_active_subscription(123, &request) + .await + .unwrap(); + + assert_eq!(result.task_id, Some("task-delete-region".to_string())); +} #[tokio::test] async fn test_get_regions_from_active_active_subscription() {