···55use futures_util::TryStreamExt;
66use ::http::StatusCode;
7788+use crate::config::{AppConfig};
89use crate::docker::{self, types::*};
9101011#[derive(Clone)]
1112pub struct AppStateWithContainerMap {
1212- pub container_map: Arc<Mutex<HashMap<String, Option<String>>>>, // <- Mutex is necessary to mutate safely across threads
1313+ pub container_map: Arc<Mutex<HashMap<String, Option<bool>>>>, // <- Mutex is necessary to mutate safely across threads
1414+}
1515+1616+macro_rules! is {
1717+ ($cond:expr; $if:expr; $else:expr) => {
1818+ if $cond { $if } else { $else }
1919+ };
1320}
14211522pub async fn forward(
···1724 body: ntex::util::Bytes,
1825 client: web::types::State<http::Client>,
1926 forward_url: web::types::State<url::Url>,
2020- container_names: web::types::State<Vec<String>>,
2121- scrub_env: web::types::State<bool>,
2727+ app_config: web::types::State<AppConfig>,
2228 data: web::types::State<AppStateWithContainerMap>
2329) -> Result<web::HttpResponse, web::Error> {
2430 let mut new_url = forward_url.get_ref().clone();
···42484349 // filter all containers to only those that have values from CONTAINER_NAMES includes in their names
4450 let filtered_containers = containers.into_iter()
4545- .filter(|&con| docker::is_container_named(con, &container_names.get_ref()))
5151+ .filter(|&con| docker::container_summary_match(con, &app_config.get_ref().container_names, &app_config.get_ref().container_labels))
4652 .collect::<Vec<&ContainerSummary>>();
47534854 let fresp = web::HttpResponse::build(res.status()).json(&filtered_containers);
···5965 let mut cm = data.container_map.lock().unwrap();
60666167 // if the map does not already include the container id-name then we try to get it with our own request to docker api
6262- if !cm.contains_key(&m.id) {
6868+ // or if we encountered an error last time then try again
6969+ if !cm.contains_key(&m.id) || cm.get(&m.id).unwrap().is_none() {
6370 debug!("Requested container Id not in map, trying to inspect: {}", &m.id);
6464- let name_res = docker::get_container_name(&forward_url.to_string(), &m.id).await;
6565- match name_res {
6666- Ok(name) => {
6767- debug!("Container Id {} has name '{}'", &m.id, &name);
6868- cm.insert(m.id.clone(), Some(name));
7171+ let info_res = docker::get_container_info(&forward_url.to_string(), &m.id).await;
7272+ match info_res {
7373+ Ok((name, labels)) => {
7474+ let is_container_match = docker::match_labels_or_names(&app_config.get_ref().container_names, &app_config.get_ref().container_labels, &Vec::from([name.clone()]), &labels);
7575+ debug!("Container Id {} with name '{}' {} valid", &m.id, name, is!(is_container_match; "is";"is not"));
7676+ cm.insert(m.id.clone(), Some(is_container_match));
6977 }
7078 Err(e) => {
7179 warn!("Could not inspect container {}: {e}", &m.id);
7272- cm.insert(m.id.clone(), None);
8080+ if e.to_string().contains("No such container") {
8181+ cm.insert(m.id.clone(), Some(false));
8282+ } else {
8383+ // if the error was not a 404 then allow trying again later
8484+ cm.insert(m.id.clone(), None);
8585+ }
7386 }
7487 }
7588 }
76897790 // then we try to get the name from the stateful hashmap
7878- let name_val = cm.get(&m.id).unwrap();
9191+ let allowed = cm.get(&m.id).unwrap();
79928080- match name_val {
9393+ match allowed {
8194 Some(n) => {
8295 // only return if a response if requested container has a name that includes values from CONTAINER_NAMES
8383- if container_names.get_ref().iter().any(|x| n.contains(x)) {
9696+ if *n {
84978598 // if the route resource is specifically the Container Inspect API
8699 // then we may need to scrub Envs if SCRUB_ENVS=true
···8810189102 client_resp.content_type("application/json");
901039191- if *scrub_env.get_ref() {
104104+ if app_config.get_ref().scrub_envs {
92105 let mut container = res.json::<ContainerInspect>().await.unwrap();
93106 container.config.as_mut().unwrap().env = Some(Vec::new());
94107 Ok(client_resp.json(&container))
···101114 Ok(client_resp.streaming(res.into_stream()))
102115 }
103116 } else {
104104- debug!("Container {} does not include container filter name, 404ing...", &m.id);
117117+ debug!("Container {} does not match container filters, 404ing...", &m.id);
105118 client_resp.status(StatusCode::NOT_FOUND);
106119 Ok(client_resp.json(&DockerErrorMessage { message: format!("No such container: {}", &m.id)}))
107120 }