rightsize_modules/spring_cloud_config.rs
1//! A Spring Cloud Config Server container, ready-checked via its actuator health
2//! endpoint.
3//!
4//! Callers wanting the classpath/filesystem-backed environment repository (no
5//! external git remote required — the default, git-backed repository needs a
6//! configured URI to boot at all) should chain
7//! `.with_env("SPRING_PROFILES_ACTIVE", "native")` before `start()`. That decision
8//! belongs to the caller/test, not this module: the module itself does not set this
9//! profile.
10
11use rightsize::{Container, ContainerGuard, Result, Wait};
12
13/// A Spring Cloud Config Server container.
14pub struct SpringCloudConfigContainer(Container);
15
16impl SpringCloudConfigContainer {
17 const PORT: u16 = 8888;
18
19 /// Builds a container from the pinned default image
20 /// (`hyness/spring-cloud-config-server:latest`).
21 pub fn new() -> Self {
22 Self::with_image("hyness/spring-cloud-config-server:latest")
23 }
24
25 /// Builds a container from a caller-chosen image.
26 pub fn with_image(image: &str) -> Self {
27 Self(
28 Container::new(image)
29 .with_exposed_ports(&[Self::PORT])
30 .waiting_for(Wait::for_http("/actuator/health").for_port(Self::PORT))
31 // Paketo's memory calculator sizes this JVM image's fixed regions
32 // (~688M) above microsandbox's default microVM RAM (~450M);
33 // this is the reason with_memory_limit exists on the module.
34 .with_memory_limit(1024),
35 )
36 }
37
38 /// Sets a single environment variable for the container process — a thin
39 /// passthrough to [`Container::with_env`], since this newtype wraps `Container`
40 /// rather than exposing it directly, so this passthrough is how a caller reaches
41 /// the same builder surface. Callers needing the classpath-backed `native`
42 /// profile call this before `start()` — see the module doc.
43 pub fn with_env(mut self, key: &str, value: &str) -> Self {
44 self.0 = self.0.with_env(key, value);
45 self
46 }
47
48 /// Boots the container.
49 pub async fn start(self) -> Result<SpringCloudConfigGuard> {
50 crate::register_default_backends();
51 Ok(SpringCloudConfigGuard(self.0.start().await?))
52 }
53}
54
55impl Default for SpringCloudConfigContainer {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61/// The running guard for a [`SpringCloudConfigContainer`].
62pub struct SpringCloudConfigGuard(ContainerGuard);
63
64impl SpringCloudConfigGuard {
65 /// The config server's base URI for the running container.
66 pub fn uri(&self) -> String {
67 format!(
68 "http://{}:{}",
69 self.0.host(),
70 self.0
71 .get_mapped_port(SpringCloudConfigContainer::PORT)
72 .unwrap()
73 )
74 }
75
76 /// Stops and removes the container, releasing its host port.
77 pub async fn stop(self) -> Result<()> {
78 self.0.stop().await
79 }
80}
81
82impl std::ops::Deref for SpringCloudConfigGuard {
83 type Target = ContainerGuard;
84 fn deref(&self) -> &ContainerGuard {
85 &self.0
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn with_image_smoke() {
95 let _ = SpringCloudConfigContainer::new();
96 }
97}