commit 5dd316e79476797a698d46a2e5699033134176a9 from: murilo ijanc date: Sat Nov 29 21:59:44 2025 UTC Add kopsctl login aws with sso commit - 8b43cacff071605d7df7f2c9e7af81a0c78d36aa commit + 5dd316e79476797a698d46a2e5699033134176a9 blob - d41a3be9a1ce49b0400358313e781c365b7c4a6e blob + cddf32fda8c3b4f2ffaa843912bcca4858945bf2 --- Cargo.lock +++ Cargo.lock @@ -643,6 +643,12 @@ dependencies = [ ] [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -718,6 +724,16 @@ source = "registry+https://github.com/rust-lang/crates checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] name = "concurrent-queue" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1667,6 +1683,28 @@ source = "registry+https://github.com/rust-lang/crates checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[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", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] name = "jobserver" version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1830,12 +1868,16 @@ name = "kopsctl" version = "0.1.0" dependencies = [ "anyhow", + "aws-config", + "aws-types", "clap", "dialoguer", + "kops_aws_sso", "kops_log", "kops_protocol", "tokio", "tracing", + "webbrowser", ] [[package]] @@ -1843,6 +1885,7 @@ name = "kopsd" version = "0.1.0" dependencies = [ "anyhow", + "chrono", "clap", "config", "daemonize", @@ -2085,6 +2128,12 @@ dependencies = [ ] [[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] name = "nu-ansi-term" version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2118,6 +2167,31 @@ dependencies = [ ] [[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "objc2", +] + +[[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2543,6 +2617,15 @@ source = "registry+https://github.com/rust-lang/crates checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] name = "schannel" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3308,6 +3391,16 @@ source = "registry+https://github.com/rust-lang/crates checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" [[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3377,6 +3470,41 @@ dependencies = [ ] [[package]] +name = "web-sys" +version = "0.3.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97" +dependencies = [ + "core-foundation 0.10.1", + "jni", + "log", + "ndk-context", + "objc2", + "objc2-foundation", + "url", + "web-sys", +] + +[[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" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3443,6 +3571,15 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" @@ -3470,6 +3607,21 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" @@ -3503,6 +3655,12 @@ dependencies = [ [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" @@ -3515,6 +3673,12 @@ checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cea [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" @@ -3527,6 +3691,12 @@ checksum = "b9d782e804c2f632e395708e99a94275910eb9100b [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" @@ -3551,6 +3721,12 @@ checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559ae [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" @@ -3563,6 +3739,12 @@ checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c8925 [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" @@ -3575,6 +3757,12 @@ checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29 [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" @@ -3587,6 +3775,12 @@ checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536 [[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" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" blob - 9e54c2456c150d9dfe7a305a792fe99c4975219b blob + f62f88dfbbf876b7f19291bc78d6c856a115d1f8 --- Cargo.toml +++ Cargo.toml @@ -28,6 +28,7 @@ unused_unsafe = "warn" all = { level = "warn", priority = -1 } [workspace.dependencies] +kops_aws_sso = { version = "=0.1.0", path = "crates/kops_aws_sso" } kops_log = { version = "=0.1.0", path = "crates/kops_log" } kops_protocol = { version = "=0.1.0", path = "crates/kops_protocol" } @@ -36,6 +37,7 @@ aws-config = { version = "=1.8.11", features = ["behav aws-credential-types = "=1.2.10" aws-sdk-sso = "=1.90.0" aws-sdk-ssooidc = "=1.92.0" +aws-types = "=1.3.10" bincode = "=2.0.1" chrono = { version = "0.4", features = ["clock", "serde"] } clap = { version = "=4.5.53", features = ["derive", "env"] } blob - 2c19e0b681afb8959610e668a41f2be2e5f590bb blob + f56d5d4bcc487b5ef9a0ab4f3df36a1fd084876b --- crates/kops_aws_sso/src/lib.rs +++ crates/kops_aws_sso/src/lib.rs @@ -87,6 +87,10 @@ where .await .context("failed to start device authorization")?; + let verification_uri = device_auth + .verification_uri_complete() + .ok_or(anyhow!("missing verification URI"))?; + let device_code = must(device_auth.device_code(), "device_code")?; let verification_uri = device_auth .verification_uri_complete() blob - 67012d53d2e0050150e27f10dbbbb755ee53f201 blob + e366e724d0780028563ba609e69247912d6eb450 --- crates/kops_protocol/src/lib.rs +++ crates/kops_protocol/src/lib.rs @@ -27,7 +27,7 @@ pub enum Request { /// Health-check: the daemon must reply with `Response::Pong`. Ping, - Login, + Login(LoginRequest), Pods(PodsRequest), Env(EnvRequest), @@ -42,6 +42,7 @@ pub enum Response { /// Response for `Request::Ping`, Pong, + /// Login successfully registered in daemon LoginOk, Version(VersionInfo), @@ -164,3 +165,30 @@ fn extract_status_fields( (reason, message, ready, restarts) } + +#[derive(Debug, Encode, Decode)] +pub struct LoginRequest { + /// Logical profile name, e.g. "dev" or "prod". + pub name: String, + + /// Optional region associated with this profile. + pub region: Option, + + /// AWS account ID where this role is valid. + pub account_id: String, + + /// IAM role name assumed via SSO. + pub role_name: String, + + /// AWS access key ID from SSO. + pub access_key_id: String, + + /// AWS secret access key from SSO. + pub secret_access_key: String, + + /// Temporary session token from SSO. + pub session_token: String, + + /// Expiration of this session as Unix epoch milliseconds (UTC). + pub expires_at_epoch_ms: i64, +} blob - f681f50610a0ae1ffb26827e7357f7f1914c68c2 blob + c04aedf8fc4b9e16e60484aa925f646a89eafda1 --- kopsctl/Cargo.toml +++ kopsctl/Cargo.toml @@ -14,12 +14,16 @@ description.workspace = true [dependencies] anyhow.workspace = true +aws-config.workspace = true +aws-types.workspace = true clap.workspace = true dialoguer.workspace = true +kops_aws_sso.workspace = true kops_log.workspace = true kops_protocol.workspace = true tokio.workspace = true tracing.workspace = true +webbrowser.workspace = true [lints] workspace = true blob - 1d33f4409dbe65886df7591f74bef53c64dbaa1c blob + 1fdf4a4d1689ac189eb9d0cfca5ad5f7ae3f6817 --- kopsctl/src/cmd/login.rs +++ kopsctl/src/cmd/login.rs @@ -14,24 +14,115 @@ // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // -use anyhow::{Result, bail}; +use anyhow::{Result, anyhow, bail}; +use aws_config::BehaviorVersion; +use aws_types::region::Region; +use kops_aws_sso::{SsoLoginConfig, login_device_flow}; +use kops_protocol::{LoginRequest, Request, Response}; -use kops_protocol::{Request, Response}; - use crate::helper::send_request; -pub async fn execute() -> Result<()> { - let resp = send_request(Request::Login).await?; +pub async fn execute(name: String, region: Option) -> Result<()> { + let region = region + .or_else(|| std::env::var("AWS_REGION").ok()) + .unwrap_or_else(|| "us-east-1".to_string()); + let start_url = std::env::var("KOPS_SSO_START_URL") + .map_err(|_| anyhow!("KOPS_SSO_START_URL not set"))?; + let account_id = std::env::var("KOPS_SSO_ACCOUNT_ID") + .map_err(|_| anyhow!("KOPS_SSO_ACCOUNT_ID not set"))?; + let role_name = std::env::var("KOPS_SSO_ROLE_NAME") + .map_err(|_| anyhow!("KOPS_SSO_ROLE_NAME not set"))?; + + let client_name = format!("kops"); + + let sso_cfg = SsoLoginConfig { + region: region.clone(), + start_url, + account_id: account_id.clone(), + role_name: role_name.clone(), + client_name, + }; + + let sdk_config = aws_config::from_env() + .region(Region::new(region.clone())) + .load() + .await; + + println!("Starting AWS SSO device flow for profile '{name}'..."); + println!("Region : {region}"); + println!("Account ID : {account_id}"); + println!("Role name : {role_name}"); + println!(); + + let session = login_device_flow(&sdk_config, &sso_cfg, |info| { + println!("SSO user code : {}", info.user_code); + println!("Verification URL : {}", info.verification_uri); + + if let Some(full) = &info.verification_uri_complete { + println!("Verification (full) : {full}"); + + if let Err(err) = webbrowser::open(full) { + eprintln!("Failed to open browser automatically: {err}"); + eprintln!("Please open the URL manually."); + } else { + println!( + "Browser opened automatically, please finish authentication." + ); + } + } else if let Err(err) = webbrowser::open(&info.verification_uri) { + eprintln!("Failed to open browser automatically: {err}"); + eprintln!("Please open the URL manually."); + } else { + println!( + "Browser opened automatically, please finish authentication." + ); + } + + println!(); + println!("Waiting for AWS SSO authorization..."); + }) + .await?; + + println!( + "Successfully obtained AWS credentials for account {} role {}", + session.account_id, session.role_name + ); + + let expires_at_epoch_ms = session.expires_at.timestamp_millis(); + + let creds = session.credentials; + let access_key_id = creds.access_key_id().to_string(); + let secret_access_key = creds.secret_access_key().to_string(); + let session_token = creds + .session_token() + .ok_or_else(|| anyhow!("missing session token in AWS credentials"))? + .to_string(); + + let req = Request::Login(LoginRequest { + name: name.clone(), + region: Some(region), + account_id, + role_name, + access_key_id, + secret_access_key, + session_token, + expires_at_epoch_ms, + }); + + let resp = send_request(req).await?; + match resp { - Response::LoginOk => print_login_info(), - Response::Error { message } => bail!("reponse error {message}"), - _ => bail!("unexpected response to version"), + Response::LoginOk => { + println!( + "kopsd registered AWS session for profile '{name}' successfully." + ); + } + Response::Error { message } => { + bail!("daemon returned error on login: {message}"); + } + _ => bail!("unexpected response to login"), } Ok(()) } - -fn print_login_info() { - println!("login ok"); -} blob - 8afcb435a3252d9616c2cdd15312e411aea7d5e4 blob + 165fa0600e9635c0a977f44d3806fcf0f044f431 --- kopsctl/src/main.rs +++ kopsctl/src/main.rs @@ -34,9 +34,17 @@ enum Command { /// Ping the daemon and expect a Pong response. Ping, - /// Login to the aws - Login, + /// Login via AWS SSO and register credentials in kopsd + Login { + /// Logical name for this credential set (e.g. dev, prod) + #[arg(long)] + name: String, + /// AWS region for SSO (optional, defaults to config or us-east-1) + #[arg(long)] + region: Option, + }, + /// Show daemon and protocol version Version, @@ -97,7 +105,9 @@ async fn main() -> Result<()> { match args.command { Command::Ping => cmd::ping::execute().await?, - Command::Login => cmd::login::execute().await?, + Command::Login { name, region } => { + cmd::login::execute(name, region).await? + } Command::Version => cmd::version::execute().await?, Command::Pods { cluster, namespace, failed_only } => { cmd::pods::execute(cluster, namespace, failed_only).await? blob - b974932c59871600a915c99522dfb7e2eb3b2380 blob + d4f8871404773124280108e5f09e2bc43cb1e1e2 --- kopsd/Cargo.toml +++ kopsd/Cargo.toml @@ -14,6 +14,7 @@ description.workspace = true [dependencies] anyhow.workspace = true +chrono.workspace = true clap.workspace = true config.workspace = true daemonize.workspace = true blob - 804f99b9964ceb3f4a37a5da2acd641deab88d4d blob + 27a3846d04bd7f1ecbc20b96792e43336afde4c2 --- kopsd/src/handler.rs +++ kopsd/src/handler.rs @@ -16,13 +16,16 @@ use std::sync::Arc; +use chrono::{TimeZone, Utc}; use k8s_openapi::api::core::v1::Pod; use kops_protocol::{ - EnvEntry, EnvRequest, PodSummary, PodsRequest, Request, Response, + EnvEntry, EnvRequest, LoginRequest, PodSummary, PodsRequest, Request, + Response, }; use kube::ResourceExt; +use tracing::info; -use crate::state::DaemonState; +use crate::state::{AwsSession, DaemonState}; pub struct Handler { state: Arc, @@ -36,13 +39,46 @@ impl Handler { pub async fn handle(&self, req: Request) -> Response { match req { Request::Ping => Response::Pong, - Request::Login => Response::LoginOk, + Request::Login(login_req) => self.handle_login(login_req).await, Request::Version => self.handle_version().await, Request::Pods(p) => self.handle_pods(p).await, Request::Env(r) => self.handle_env(r).await, } } + async fn handle_login(&self, req: LoginRequest) -> Response { + info!( + "received AWS login for profile '{}' (account {} role {})", + req.name, req.account_id, req.role_name + ); + + let expires_at = Utc + .timestamp_millis_opt(req.expires_at_epoch_ms) + .single() + .unwrap_or_else(|| Utc::now()); + + let session = AwsSession { + account_id: req.account_id, + role_name: req.role_name, + region: req.region.clone(), + access_key_id: req.access_key_id, + secret_access_key: req.secret_access_key, + session_token: req.session_token, + expires_at, + }; + + match self.state.aws_sessions.lock() { + Ok(mut map) => { + map.insert(req.name.clone(), session); + info!("stored AWS session for profile '{}'", req.name); + Response::LoginOk + } + Err(_) => Response::Error { + message: "failed to lock aws_sessions map".into(), + }, + } + } + async fn handle_env(&self, req: EnvRequest) -> Response { let cluster = req .cluster blob - 537caf4d8e725986ab270adea8b30f905bab7f49 blob + da25e6bbcbb16dbed6de3816f4e9803a375b845a --- kopsd/src/server.rs +++ kopsd/src/server.rs @@ -63,11 +63,11 @@ fn run_fg(config: &KopsdConfig) -> Result<()> { .context("failed to build tokio runtime")?; rt.block_on(async move { - let mut clusters_map = std::collections::HashMap::new(); - for c in &config.cluster { - let cs = init_cluster_state(c.clone()).await.unwrap(); - clusters_map.insert(c.name.clone(), cs); - } + let clusters_map = std::collections::HashMap::new(); + // for c in &config.cluster { + // let cs = init_cluster_state(c.clone()).await.unwrap(); + // // clusters_map.insert(c.name.clone(), cs); + // } let default_cluster = config .kops @@ -75,8 +75,15 @@ fn run_fg(config: &KopsdConfig) -> Result<()> { .clone() .unwrap_or_else(|| config.cluster[0].name.clone()); - let state = - Arc::new(DaemonState { clusters: clusters_map, default_cluster }); + // let state = + // Arc::new(DaemonState { clusters: clusters_map, default_cluster }); + let state = Arc::new(DaemonState { + clusters: clusters_map, + default_cluster, + aws_sessions: std::sync::Mutex::new( + std::collections::HashMap::new(), + ), + }); // for c in config.cluster.clone() { // let cluster_name = c.name.clone(); blob - e1fa0e1dd4458edfb8fd27f4644d3fe4367863b9 blob + 2bfcf0a77e38dfd27b14ab30f08961d9250275e7 --- kopsd/src/state.rs +++ kopsd/src/state.rs @@ -15,11 +15,24 @@ // use std::collections::HashMap; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; +use chrono::{DateTime, Utc}; use k8s_openapi::api::core::v1::Pod; use kube::runtime::reflector::Store; +/// AWS session stored in daemon memory. +#[derive(Clone)] +pub struct AwsSession { + pub account_id: String, + pub role_name: String, + pub region: Option, + pub access_key_id: String, + pub secret_access_key: String, + pub session_token: String, + pub expires_at: DateTime, +} + /// Logical name of the cluster (from config). pub type ClusterName = String; @@ -27,12 +40,21 @@ pub type ClusterName = String; pub struct DaemonState { pub clusters: HashMap>, pub default_cluster: ClusterName, + + /// AWS sessions keyed by logical profile name ("dev", "prod", ...). + pub aws_sessions: Mutex>, } impl DaemonState { pub fn default_cluster(&self) -> &str { &self.default_cluster } + + #[allow(dead_code)] + pub fn get_session(&self, name: &str) -> Option { + let sessions = self.aws_sessions.lock().ok()?; + sessions.get(name).cloned() + } } /// Per-cluster in-memory state backed by a reflector Store.