mirror of
https://github.com/dani-garcia/vaultwarden
synced 2024-12-15 01:53:43 +01:00
Add Kubernetes environment detection (#4290)
Also check if we are running within a Kubernetes environment. These do not always run using Docker or Podman of course. Also renamed all the functions and variables to use `container` instead of `docker`.
This commit is contained in:
parent
77cd5b5954
commit
569add453d
5 changed files with 29 additions and 26 deletions
|
@ -23,8 +23,8 @@ use crate::{
|
||||||
error::{Error, MapResult},
|
error::{Error, MapResult},
|
||||||
mail,
|
mail,
|
||||||
util::{
|
util::{
|
||||||
docker_base_image, format_naive_datetime_local, get_display_size, get_reqwest_client, is_running_in_docker,
|
container_base_image, format_naive_datetime_local, get_display_size, get_reqwest_client,
|
||||||
NumberOrString,
|
is_running_in_container, NumberOrString,
|
||||||
},
|
},
|
||||||
CONFIG, VERSION,
|
CONFIG, VERSION,
|
||||||
};
|
};
|
||||||
|
@ -608,7 +608,7 @@ use cached::proc_macro::cached;
|
||||||
/// Cache this function to prevent API call rate limit. Github only allows 60 requests per hour, and we use 3 here already.
|
/// Cache this function to prevent API call rate limit. Github only allows 60 requests per hour, and we use 3 here already.
|
||||||
/// It will cache this function for 300 seconds (5 minutes) which should prevent the exhaustion of the rate limit.
|
/// It will cache this function for 300 seconds (5 minutes) which should prevent the exhaustion of the rate limit.
|
||||||
#[cached(time = 300, sync_writes = true)]
|
#[cached(time = 300, sync_writes = true)]
|
||||||
async fn get_release_info(has_http_access: bool, running_within_docker: bool) -> (String, String, String) {
|
async fn get_release_info(has_http_access: bool, running_within_container: bool) -> (String, String, String) {
|
||||||
// If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway.
|
// If the HTTP Check failed, do not even attempt to check for new versions since we were not able to connect with github.com anyway.
|
||||||
if has_http_access {
|
if has_http_access {
|
||||||
(
|
(
|
||||||
|
@ -625,9 +625,9 @@ async fn get_release_info(has_http_access: bool, running_within_docker: bool) ->
|
||||||
}
|
}
|
||||||
_ => "-".to_string(),
|
_ => "-".to_string(),
|
||||||
},
|
},
|
||||||
// Do not fetch the web-vault version when running within Docker.
|
// Do not fetch the web-vault version when running within a container.
|
||||||
// The web-vault version is embedded within the container it self, and should not be updated manually
|
// The web-vault version is embedded within the container it self, and should not be updated manually
|
||||||
if running_within_docker {
|
if running_within_container {
|
||||||
"-".to_string()
|
"-".to_string()
|
||||||
} else {
|
} else {
|
||||||
match get_json_api::<GitRelease>(
|
match get_json_api::<GitRelease>(
|
||||||
|
@ -681,7 +681,7 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute some environment checks
|
// Execute some environment checks
|
||||||
let running_within_docker = is_running_in_docker();
|
let running_within_container = is_running_in_container();
|
||||||
let has_http_access = has_http_access().await;
|
let has_http_access = has_http_access().await;
|
||||||
let uses_proxy = env::var_os("HTTP_PROXY").is_some()
|
let uses_proxy = env::var_os("HTTP_PROXY").is_some()
|
||||||
|| env::var_os("http_proxy").is_some()
|
|| env::var_os("http_proxy").is_some()
|
||||||
|
@ -695,7 +695,7 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn)
|
||||||
};
|
};
|
||||||
|
|
||||||
let (latest_release, latest_commit, latest_web_build) =
|
let (latest_release, latest_commit, latest_web_build) =
|
||||||
get_release_info(has_http_access, running_within_docker).await;
|
get_release_info(has_http_access, running_within_container).await;
|
||||||
|
|
||||||
let ip_header_name = match &ip_header.0 {
|
let ip_header_name = match &ip_header.0 {
|
||||||
Some(h) => h,
|
Some(h) => h,
|
||||||
|
@ -710,8 +710,8 @@ async fn diagnostics(_token: AdminToken, ip_header: IpHeader, mut conn: DbConn)
|
||||||
"web_vault_enabled": &CONFIG.web_vault_enabled(),
|
"web_vault_enabled": &CONFIG.web_vault_enabled(),
|
||||||
"web_vault_version": web_vault_version.version.trim_start_matches('v'),
|
"web_vault_version": web_vault_version.version.trim_start_matches('v'),
|
||||||
"latest_web_build": latest_web_build,
|
"latest_web_build": latest_web_build,
|
||||||
"running_within_docker": running_within_docker,
|
"running_within_container": running_within_container,
|
||||||
"docker_base_image": if running_within_docker { docker_base_image() } else { "Not applicable" },
|
"container_base_image": if running_within_container { container_base_image() } else { "Not applicable" },
|
||||||
"has_http_access": has_http_access,
|
"has_http_access": has_http_access,
|
||||||
"ip_header_exists": &ip_header.0.is_some(),
|
"ip_header_exists": &ip_header.0.is_some(),
|
||||||
"ip_header_match": ip_header_name == CONFIG.ip_header(),
|
"ip_header_match": ip_header_name == CONFIG.ip_header(),
|
||||||
|
|
10
src/main.rs
10
src/main.rs
|
@ -88,7 +88,7 @@ pub use config::CONFIG;
|
||||||
pub use error::{Error, MapResult};
|
pub use error::{Error, MapResult};
|
||||||
use rocket::data::{Limits, ToByteUnit};
|
use rocket::data::{Limits, ToByteUnit};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
pub use util::is_running_in_docker;
|
pub use util::is_running_in_container;
|
||||||
|
|
||||||
#[rocket::main]
|
#[rocket::main]
|
||||||
async fn main() -> Result<(), Error> {
|
async fn main() -> Result<(), Error> {
|
||||||
|
@ -415,7 +415,7 @@ async fn check_data_folder() {
|
||||||
let path = Path::new(data_folder);
|
let path = Path::new(data_folder);
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
error!("Data folder '{}' doesn't exist.", data_folder);
|
error!("Data folder '{}' doesn't exist.", data_folder);
|
||||||
if is_running_in_docker() {
|
if is_running_in_container() {
|
||||||
error!("Verify that your data volume is mounted at the correct location.");
|
error!("Verify that your data volume is mounted at the correct location.");
|
||||||
} else {
|
} else {
|
||||||
error!("Create the data folder and try again.");
|
error!("Create the data folder and try again.");
|
||||||
|
@ -427,9 +427,9 @@ async fn check_data_folder() {
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if is_running_in_docker()
|
if is_running_in_container()
|
||||||
&& std::env::var("I_REALLY_WANT_VOLATILE_STORAGE").is_err()
|
&& std::env::var("I_REALLY_WANT_VOLATILE_STORAGE").is_err()
|
||||||
&& !docker_data_folder_is_persistent(data_folder).await
|
&& !container_data_folder_is_persistent(data_folder).await
|
||||||
{
|
{
|
||||||
error!(
|
error!(
|
||||||
"No persistent volume!\n\
|
"No persistent volume!\n\
|
||||||
|
@ -448,7 +448,7 @@ async fn check_data_folder() {
|
||||||
/// A none persistent volume in either Docker or Podman is represented by a 64 alphanumerical string.
|
/// A none persistent volume in either Docker or Podman is represented by a 64 alphanumerical string.
|
||||||
/// If we detect this string, we will alert about not having a persistent self defined volume.
|
/// If we detect this string, we will alert about not having a persistent self defined volume.
|
||||||
/// This probably means that someone forgot to add `-v /path/to/vaultwarden_data/:/data`
|
/// This probably means that someone forgot to add `-v /path/to/vaultwarden_data/:/data`
|
||||||
async fn docker_data_folder_is_persistent(data_folder: &str) -> bool {
|
async fn container_data_folder_is_persistent(data_folder: &str) -> bool {
|
||||||
if let Ok(mountinfo) = File::open("/proc/self/mountinfo").await {
|
if let Ok(mountinfo) = File::open("/proc/self/mountinfo").await {
|
||||||
// Since there can only be one mountpoint to the DATA_FOLDER
|
// Since there can only be one mountpoint to the DATA_FOLDER
|
||||||
// We do a basic check for this mountpoint surrounded by a space.
|
// We do a basic check for this mountpoint surrounded by a space.
|
||||||
|
|
4
src/static/scripts/admin_diagnostics.js
vendored
4
src/static/scripts/admin_diagnostics.js
vendored
|
@ -77,7 +77,7 @@ async function generateSupportString(event, dj) {
|
||||||
supportString += `* Vaultwarden version: v${dj.current_release}\n`;
|
supportString += `* Vaultwarden version: v${dj.current_release}\n`;
|
||||||
supportString += `* Web-vault version: v${dj.web_vault_version}\n`;
|
supportString += `* Web-vault version: v${dj.web_vault_version}\n`;
|
||||||
supportString += `* OS/Arch: ${dj.host_os}/${dj.host_arch}\n`;
|
supportString += `* OS/Arch: ${dj.host_os}/${dj.host_arch}\n`;
|
||||||
supportString += `* Running within Docker: ${dj.running_within_docker} (Base: ${dj.docker_base_image})\n`;
|
supportString += `* Running within a container: ${dj.running_within_container} (Base: ${dj.container_base_image})\n`;
|
||||||
supportString += "* Environment settings overridden: ";
|
supportString += "* Environment settings overridden: ";
|
||||||
if (dj.overrides != "") {
|
if (dj.overrides != "") {
|
||||||
supportString += "true\n";
|
supportString += "true\n";
|
||||||
|
@ -179,7 +179,7 @@ function initVersionCheck(dj) {
|
||||||
}
|
}
|
||||||
checkVersions("server", serverInstalled, serverLatest, serverLatestCommit);
|
checkVersions("server", serverInstalled, serverLatest, serverLatestCommit);
|
||||||
|
|
||||||
if (!dj.running_within_docker) {
|
if (!dj.running_within_container) {
|
||||||
const webInstalled = dj.web_vault_version;
|
const webInstalled = dj.web_vault_version;
|
||||||
const webLatest = dj.latest_web_build;
|
const webLatest = dj.latest_web_build;
|
||||||
checkVersions("web", webInstalled, webLatest);
|
checkVersions("web", webInstalled, webLatest);
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
<span id="web-installed">{{page_data.web_vault_version}}</span>
|
<span id="web-installed">{{page_data.web_vault_version}}</span>
|
||||||
</dd>
|
</dd>
|
||||||
{{#unless page_data.running_within_docker}}
|
{{#unless page_data.running_within_container}}
|
||||||
<dt class="col-sm-5">Web Latest
|
<dt class="col-sm-5">Web Latest
|
||||||
<span class="badge bg-secondary d-none" id="web-failed" title="Unable to determine latest version.">Unknown</span>
|
<span class="badge bg-secondary d-none" id="web-failed" title="Unable to determine latest version.">Unknown</span>
|
||||||
</dt>
|
</dt>
|
||||||
|
@ -59,12 +59,12 @@
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
<span class="d-block"><b>{{ page_data.host_os }} / {{ page_data.host_arch }}</b></span>
|
<span class="d-block"><b>{{ page_data.host_os }} / {{ page_data.host_arch }}</b></span>
|
||||||
</dd>
|
</dd>
|
||||||
<dt class="col-sm-5">Running within Docker</dt>
|
<dt class="col-sm-5">Running within a container</dt>
|
||||||
<dd class="col-sm-7">
|
<dd class="col-sm-7">
|
||||||
{{#if page_data.running_within_docker}}
|
{{#if page_data.running_within_container}}
|
||||||
<span class="d-block"><b>Yes (Base: {{ page_data.docker_base_image }})</b></span>
|
<span class="d-block"><b>Yes (Base: {{ page_data.container_base_image }})</b></span>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#unless page_data.running_within_docker}}
|
{{#unless page_data.running_within_container}}
|
||||||
<span class="d-block"><b>No</b></span>
|
<span class="d-block"><b>No</b></span>
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
</dd>
|
</dd>
|
||||||
|
|
13
src/util.rs
13
src/util.rs
|
@ -531,14 +531,17 @@ pub fn parse_date(date: &str) -> NaiveDateTime {
|
||||||
// Deployment environment methods
|
// Deployment environment methods
|
||||||
//
|
//
|
||||||
|
|
||||||
/// Returns true if the program is running in Docker or Podman.
|
/// Returns true if the program is running in Docker, Podman or Kubernetes.
|
||||||
pub fn is_running_in_docker() -> bool {
|
pub fn is_running_in_container() -> bool {
|
||||||
Path::new("/.dockerenv").exists() || Path::new("/run/.containerenv").exists()
|
Path::new("/.dockerenv").exists()
|
||||||
|
|| Path::new("/run/.containerenv").exists()
|
||||||
|
|| Path::new("/run/secrets/kubernetes.io").exists()
|
||||||
|
|| Path::new("/var/run/secrets/kubernetes.io").exists()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Simple check to determine on which docker base image vaultwarden is running.
|
/// Simple check to determine on which container base image vaultwarden is running.
|
||||||
/// We build images based upon Debian or Alpine, so these we check here.
|
/// We build images based upon Debian or Alpine, so these we check here.
|
||||||
pub fn docker_base_image() -> &'static str {
|
pub fn container_base_image() -> &'static str {
|
||||||
if Path::new("/etc/debian_version").exists() {
|
if Path::new("/etc/debian_version").exists() {
|
||||||
"Debian"
|
"Debian"
|
||||||
} else if Path::new("/etc/alpine-release").exists() {
|
} else if Path::new("/etc/alpine-release").exists() {
|
||||||
|
|
Loading…
Reference in a new issue