feat: Add Kubernetes Module (#404)
Adds a Kubernetes module, which works by parsing kubeconfig.
This commit is contained in:
parent
6888f3619a
commit
9fc5a43355
|
@ -402,6 +402,11 @@ dependencies = [
|
||||||
"vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"vcpkg 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.8"
|
version = "0.4.8"
|
||||||
|
@ -772,6 +777,7 @@ dependencies = [
|
||||||
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1002,6 +1008,14 @@ dependencies = [
|
||||||
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yaml-rust"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
|
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
@ -1051,6 +1065,7 @@ dependencies = [
|
||||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||||
"checksum libgit2-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a30f8637eb59616ee3b8a00f6adff781ee4ddd8343a615b8238de756060cc1b3"
|
"checksum libgit2-sys 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a30f8637eb59616ee3b8a00f6adff781ee4ddd8343a615b8238de756060cc1b3"
|
||||||
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
|
"checksum libz-sys 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2eb5e43362e38e2bca2fd5f5134c4d4564a23a5c28e9b95411652021a8675ebe"
|
||||||
|
"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
|
||||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||||
"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
|
"checksum mach 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "86dd2487cdfea56def77b88438a2c915fb45113c5319bfe7e14306ca4cd0b0e1"
|
||||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||||
|
@ -1126,3 +1141,4 @@ dependencies = [
|
||||||
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
|
||||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
|
"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
|
||||||
|
"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
|
||||||
|
|
|
@ -85,6 +85,7 @@ The prompt shows information you need while you're working, while staying sleek
|
||||||
- `✘` — deleted files
|
- `✘` — deleted files
|
||||||
- Execution time of the last command if it exceeds the set threshold
|
- Execution time of the last command if it exceeds the set threshold
|
||||||
- Indicator for jobs in the background (`✦`)
|
- Indicator for jobs in the background (`✦`)
|
||||||
|
- Current Kubernetes Cluster and Namespace (`☸`)
|
||||||
|
|
||||||
## 🚀 Installation
|
## 🚀 Installation
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,7 @@ The default `prompt_order` is used to define the order in which modules are show
|
||||||
prompt_order = [
|
prompt_order = [
|
||||||
"username",
|
"username",
|
||||||
"hostname",
|
"hostname",
|
||||||
|
"kubernetes",
|
||||||
"directory",
|
"directory",
|
||||||
"git_branch",
|
"git_branch",
|
||||||
"git_state",
|
"git_state",
|
||||||
|
@ -528,6 +529,35 @@ symbol = "+ "
|
||||||
threshold = 4
|
threshold = 4
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Kubernetes
|
||||||
|
|
||||||
|
Displays the current Kubernetes context name and, if set, the namespace from
|
||||||
|
the kubeconfig file. The namespace needs to be set in the kubeconfig file, this
|
||||||
|
can be done via `kubectl config set-context starship-cluster --namespace
|
||||||
|
astronaut`. If the `$KUBECONFIG` env var is set the module will use that if
|
||||||
|
not it will use the `~/.kube/config`.
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
| ---------- | ------------- | --------------------------------------------------- |
|
||||||
|
| `symbol` | `"☸ "` | The symbol used before displaying the Cluster info. |
|
||||||
|
| `style` | `"bold blue"` | The style for the module. |
|
||||||
|
| `disabled` | `false` | Disables the `kubernetes` module |
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# ~/.config/starship.toml
|
||||||
|
|
||||||
|
[kubernetes]
|
||||||
|
symbol = "⛵ "
|
||||||
|
style = "dim green"
|
||||||
|
disabled = true
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
## Line Break
|
## Line Break
|
||||||
|
|
||||||
The `line_break` module separates the prompt into two lines.
|
The `line_break` module separates the prompt into two lines.
|
||||||
|
|
|
@ -45,6 +45,7 @@ chrono = "0.4"
|
||||||
sysinfo = "0.9.5"
|
sysinfo = "0.9.5"
|
||||||
byte-unit = "3.0.3"
|
byte-unit = "3.0.3"
|
||||||
starship_module_config_derive = { version = "0.20", path = "../starship_module_config_derive" }
|
starship_module_config_derive = { version = "0.20", path = "../starship_module_config_derive" }
|
||||||
|
yaml-rust = "0.4"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.1.0"
|
tempfile = "3.1.0"
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub const ALL_MODULES: &[&str] = &[
|
||||||
"hostname",
|
"hostname",
|
||||||
"java",
|
"java",
|
||||||
"jobs",
|
"jobs",
|
||||||
|
"kubernetes",
|
||||||
"line_break",
|
"line_break",
|
||||||
"memory_usage",
|
"memory_usage",
|
||||||
"nix_shell",
|
"nix_shell",
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
use ansi_term::Color;
|
||||||
|
use dirs;
|
||||||
|
use yaml_rust::YamlLoader;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::path;
|
||||||
|
|
||||||
|
use super::{Context, Module};
|
||||||
|
use crate::utils;
|
||||||
|
|
||||||
|
const KUBE_CHAR: &str = "☸ ";
|
||||||
|
|
||||||
|
fn get_kube_context(contents: &str) -> Option<(String, String)> {
|
||||||
|
let yaml_docs = YamlLoader::load_from_str(&contents).ok()?;
|
||||||
|
if yaml_docs.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let conf = &yaml_docs[0];
|
||||||
|
|
||||||
|
let current_ctx = conf["current-context"].as_str()?;
|
||||||
|
|
||||||
|
if current_ctx.is_empty() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ns = conf["contexts"]
|
||||||
|
.as_vec()
|
||||||
|
.and_then(|contexts| {
|
||||||
|
contexts
|
||||||
|
.iter()
|
||||||
|
.filter_map(|ctx| Some((ctx, ctx["name"].as_str()?)))
|
||||||
|
.find(|(_, name)| *name == current_ctx)
|
||||||
|
.and_then(|(ctx, _)| ctx["context"]["namespace"].as_str())
|
||||||
|
})
|
||||||
|
.unwrap_or("");
|
||||||
|
|
||||||
|
Some((current_ctx.to_string(), ns.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn module<'a>(context: &'a Context) -> Option<Module<'a>> {
|
||||||
|
let filename = match env::var("KUBECONFIG") {
|
||||||
|
Ok(path) => path::PathBuf::from(path),
|
||||||
|
Err(_) => dirs::home_dir()?.join(".kube").join("config"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let contents = utils::read_file(filename).ok()?;
|
||||||
|
|
||||||
|
match get_kube_context(&contents) {
|
||||||
|
Some(kube_cfg) => {
|
||||||
|
let (kube_ctx, kube_ns) = kube_cfg;
|
||||||
|
|
||||||
|
let mut module = context.new_module("kubernetes");
|
||||||
|
|
||||||
|
let module_style = module
|
||||||
|
.config_value_style("style")
|
||||||
|
.unwrap_or_else(|| Color::Cyan.bold());
|
||||||
|
module.set_style(module_style);
|
||||||
|
module.get_prefix().set_value("on ");
|
||||||
|
|
||||||
|
module.new_segment("symbol", KUBE_CHAR);
|
||||||
|
module.new_segment("context", &kube_ctx);
|
||||||
|
if kube_ns != "" {
|
||||||
|
module.new_segment("namespace", &format!(" ({})", kube_ns));
|
||||||
|
}
|
||||||
|
Some(module)
|
||||||
|
}
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_empty_config() {
|
||||||
|
let input = "";
|
||||||
|
let result = get_kube_context(&input);
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_no_config() {
|
||||||
|
let input = r#"
|
||||||
|
apiVersion: v1
|
||||||
|
clusters: []
|
||||||
|
contexts: []
|
||||||
|
current-context: ""
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users: []
|
||||||
|
"#;
|
||||||
|
let result = get_kube_context(&input);
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_only_context() {
|
||||||
|
let input = r#"
|
||||||
|
apiVersion: v1
|
||||||
|
clusters: []
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: test_cluster
|
||||||
|
user: test_user
|
||||||
|
name: test_context
|
||||||
|
current-context: test_context
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users: []
|
||||||
|
"#;
|
||||||
|
let result = get_kube_context(&input);
|
||||||
|
let expected = Some(("test_context".to_string(), "".to_string()));
|
||||||
|
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_context_and_ns() {
|
||||||
|
let input = r#"
|
||||||
|
apiVersion: v1
|
||||||
|
clusters: []
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: test_cluster
|
||||||
|
user: test_user
|
||||||
|
namespace: test_namespace
|
||||||
|
name: test_context
|
||||||
|
current-context: test_context
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users: []
|
||||||
|
"#;
|
||||||
|
let result = get_kube_context(&input);
|
||||||
|
let expected = Some(("test_context".to_string(), "test_namespace".to_string()));
|
||||||
|
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_multiple_contexts() {
|
||||||
|
let input = r#"
|
||||||
|
apiVersion: v1
|
||||||
|
clusters: []
|
||||||
|
contexts:
|
||||||
|
- context:
|
||||||
|
cluster: another_cluster
|
||||||
|
user: another_user
|
||||||
|
namespace: another_namespace
|
||||||
|
name: another_context
|
||||||
|
- context:
|
||||||
|
cluster: test_cluster
|
||||||
|
user: test_user
|
||||||
|
namespace: test_namespace
|
||||||
|
name: test_context
|
||||||
|
current-context: test_context
|
||||||
|
kind: Config
|
||||||
|
preferences: {}
|
||||||
|
users: []
|
||||||
|
"#;
|
||||||
|
let result = get_kube_context(&input);
|
||||||
|
let expected = Some(("test_context".to_string(), "test_namespace".to_string()));
|
||||||
|
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_broken_config() {
|
||||||
|
let input = r#"
|
||||||
|
---
|
||||||
|
dummy_string
|
||||||
|
"#;
|
||||||
|
let result = get_kube_context(&input);
|
||||||
|
let expected = None;
|
||||||
|
|
||||||
|
assert_eq!(result, expected);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ mod golang;
|
||||||
mod hostname;
|
mod hostname;
|
||||||
mod java;
|
mod java;
|
||||||
mod jobs;
|
mod jobs;
|
||||||
|
mod kubernetes;
|
||||||
mod line_break;
|
mod line_break;
|
||||||
mod memory_usage;
|
mod memory_usage;
|
||||||
mod nix_shell;
|
mod nix_shell;
|
||||||
|
@ -44,6 +45,7 @@ pub fn handle<'a>(module: &str, context: &'a Context) -> Option<Module<'a>> {
|
||||||
"git_branch" => git_branch::module(context),
|
"git_branch" => git_branch::module(context),
|
||||||
"git_state" => git_state::module(context),
|
"git_state" => git_state::module(context),
|
||||||
"git_status" => git_status::module(context),
|
"git_status" => git_status::module(context),
|
||||||
|
"kubernetes" => kubernetes::module(context),
|
||||||
"username" => username::module(context),
|
"username" => username::module(context),
|
||||||
#[cfg(feature = "battery")]
|
#[cfg(feature = "battery")]
|
||||||
"battery" => battery::module(context),
|
"battery" => battery::module(context),
|
||||||
|
|
Loading…
Reference in New Issue