|
| 1 | +use anyhow::{bail, Result}; |
| 2 | +use stackable_operator::kube::{api::DynamicObject, ResourceExt}; |
| 3 | + |
| 4 | +pub fn data_field_as_mut<'a>( |
| 5 | + value: &'a mut serde_json::Value, |
| 6 | + pointer: &str, |
| 7 | +) -> Result<&'a mut serde_json::Value> { |
| 8 | + match value.pointer_mut(pointer) { |
| 9 | + Some(field) => Ok(field), |
| 10 | + x => bail!("invalid pointer {pointer} for object {x:?}"), |
| 11 | + } |
| 12 | +} |
| 13 | + |
| 14 | +pub fn container<'a>( |
| 15 | + target: &'a mut DynamicObject, |
| 16 | + container_name: &str, |
| 17 | +) -> anyhow::Result<&'a mut serde_json::Value> { |
| 18 | + let tname = target.name_any(); |
| 19 | + let path = "template/spec/containers".split("/"); |
| 20 | + match get_or_create(target.data.pointer_mut("/spec").unwrap(), path)? { |
| 21 | + serde_json::Value::Array(containers) => { |
| 22 | + for c in containers { |
| 23 | + if c.is_object() { |
| 24 | + if let Some(serde_json::Value::String(name)) = c.get("name") { |
| 25 | + if container_name == name { |
| 26 | + return Ok(c); |
| 27 | + } |
| 28 | + } |
| 29 | + } else { |
| 30 | + anyhow::bail!("container is not a object: {:?}", c); |
| 31 | + } |
| 32 | + } |
| 33 | + anyhow::bail!("container named {container_name} not found"); |
| 34 | + } |
| 35 | + _ => anyhow::bail!("no containers found in object {tname}"), |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +/// Returns the object nested in `root` by traversing the `path` of nested keys. |
| 40 | +/// Creates any missing objects in path. |
| 41 | +/// In case of success, the returned value is either the existing object or |
| 42 | +/// serde_json::Value::Null. |
| 43 | +/// Returns an error if any of the nested objects has a type other than map. |
| 44 | +pub fn get_or_create<'a, 'b, I>( |
| 45 | + root: &'a mut serde_json::Value, |
| 46 | + path: I, |
| 47 | +) -> anyhow::Result<&'a mut serde_json::Value> |
| 48 | +where |
| 49 | + I: IntoIterator<Item = &'b str>, |
| 50 | +{ |
| 51 | + let mut iter = path.into_iter(); |
| 52 | + match iter.next() { |
| 53 | + None => Ok(root), |
| 54 | + Some(first) => { |
| 55 | + let new_root = get_or_insert_default_object(root, first)?; |
| 56 | + get_or_create(new_root, iter) |
| 57 | + } |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +/// Given a map object create or return the object corresponding to the given `key`. |
| 62 | +fn get_or_insert_default_object<'a>( |
| 63 | + value: &'a mut serde_json::Value, |
| 64 | + key: &str, |
| 65 | +) -> anyhow::Result<&'a mut serde_json::Value> { |
| 66 | + let map = match value { |
| 67 | + serde_json::Value::Object(map) => map, |
| 68 | + x @ serde_json::Value::Null => { |
| 69 | + *x = serde_json::json!({}); |
| 70 | + x.as_object_mut().unwrap() |
| 71 | + } |
| 72 | + x => anyhow::bail!("invalid type {x:?}, expected map"), |
| 73 | + }; |
| 74 | + Ok(map.entry(key).or_insert_with(|| serde_json::Value::Null)) |
| 75 | +} |
0 commit comments