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)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
|
@ -772,6 +777,7 @@ dependencies = [
|
|||
"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)",
|
||||
"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]]
|
||||
|
@ -1002,6 +1008,14 @@ dependencies = [
|
|||
"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]
|
||||
"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"
|
||||
|
@ -1051,6 +1065,7 @@ dependencies = [
|
|||
"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 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 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"
|
||||
|
@ -1126,3 +1141,4 @@ dependencies = [
|
|||
"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 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
|
||||
- Execution time of the last command if it exceeds the set threshold
|
||||
- Indicator for jobs in the background (`✦`)
|
||||
- Current Kubernetes Cluster and Namespace (`☸`)
|
||||
|
||||
## 🚀 Installation
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ The default `prompt_order` is used to define the order in which modules are show
|
|||
prompt_order = [
|
||||
"username",
|
||||
"hostname",
|
||||
"kubernetes",
|
||||
"directory",
|
||||
"git_branch",
|
||||
"git_state",
|
||||
|
@ -528,6 +529,35 @@ symbol = "+ "
|
|||
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
|
||||
|
||||
The `line_break` module separates the prompt into two lines.
|
||||
|
|
|
@ -45,6 +45,7 @@ chrono = "0.4"
|
|||
sysinfo = "0.9.5"
|
||||
byte-unit = "3.0.3"
|
||||
starship_module_config_derive = { version = "0.20", path = "../starship_module_config_derive" }
|
||||
yaml-rust = "0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.1.0"
|
||||
|
|
|
@ -20,6 +20,7 @@ pub const ALL_MODULES: &[&str] = &[
|
|||
"hostname",
|
||||
"java",
|
||||
"jobs",
|
||||
"kubernetes",
|
||||
"line_break",
|
||||
"memory_usage",
|
||||
"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 java;
|
||||
mod jobs;
|
||||
mod kubernetes;
|
||||
mod line_break;
|
||||
mod memory_usage;
|
||||
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_state" => git_state::module(context),
|
||||
"git_status" => git_status::module(context),
|
||||
"kubernetes" => kubernetes::module(context),
|
||||
"username" => username::module(context),
|
||||
#[cfg(feature = "battery")]
|
||||
"battery" => battery::module(context),
|
||||
|
|
Loading…
Reference in New Issue