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 Ok(SpringCloudConfigGuard(self.0.start().await?))
51 }
52}
53
54impl Default for SpringCloudConfigContainer {
55 fn default() -> Self {
56 Self::new()
57 }
58}
59
60/// The running guard for a [`SpringCloudConfigContainer`].
61pub struct SpringCloudConfigGuard(ContainerGuard);
62
63impl SpringCloudConfigGuard {
64 /// The config server's base URI for the running container.
65 pub fn uri(&self) -> String {
66 format!(
67 "http://{}:{}",
68 self.0.host(),
69 self.0
70 .get_mapped_port(SpringCloudConfigContainer::PORT)
71 .unwrap()
72 )
73 }
74
75 /// Stops and removes the container, releasing its host port.
76 pub async fn stop(self) -> Result<()> {
77 self.0.stop().await
78 }
79}
80
81impl std::ops::Deref for SpringCloudConfigGuard {
82 type Target = ContainerGuard;
83 fn deref(&self) -> &ContainerGuard {
84 &self.0
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91
92 #[test]
93 fn with_image_smoke() {
94 let _ = SpringCloudConfigContainer::new();
95 }
96}