| 31 | } |
| 32 | |
| 33 | fn invoke(&self, args: &[Value], context: &Context) -> Result<Value, DscError> { |
| 34 | let secret_name = args[0].as_str().ok_or_else(|| { |
| 35 | DscError::Function("secret".to_string(), t!("functions.secret.notString").to_string()) |
| 36 | })?.to_string(); |
| 37 | let vault_name: Option<String> = if args.len() > 1 { |
| 38 | args[1].as_str().map(std::string::ToString::to_string) |
| 39 | } else { |
| 40 | None |
| 41 | }; |
| 42 | |
| 43 | // we query all extensions supporting the secret method to see if any of them can provide the secret. |
| 44 | // if none can or if multiple provide different values, we return an error. |
| 45 | let extensions = context.extensions.iter() |
| 46 | .filter(|ext| ext.capabilities.contains(&Capability::Secret)) |
| 47 | .collect::<Vec<_>>(); |
| 48 | let mut secret_returned = false; |
| 49 | let mut result: String = String::new(); |
| 50 | if extensions.is_empty() { |
| 51 | return Err(DscError::Function("secret".to_string(), t!("functions.secret.noExtensions").to_string())); |
| 52 | } |
| 53 | for extension in extensions { |
| 54 | match extension.secret(&secret_name, vault_name.as_deref()) { |
| 55 | Ok(secret_result) => { |
| 56 | if let Some(secret_value) = secret_result { |
| 57 | if secret_returned && result != secret_value { |
| 58 | return Err(DscError::Function("secret".to_string(), t!("functions.secret.multipleSecrets", name = secret_name.clone()).to_string())); |
| 59 | } |
| 60 | |
| 61 | result = secret_value; |
| 62 | secret_returned = true; |
| 63 | } |
| 64 | }, |
| 65 | Err(err) => { |
| 66 | warn!("{}", t!("functions.secret.extensionReturnedError", extension = extension.type_name.clone(), error = err)); |
| 67 | } |
| 68 | } |
| 69 | } |
| 70 | if secret_returned { |
| 71 | Ok(Value::String(result)) |
| 72 | } else { |
| 73 | Err(DscError::Function("secret".to_string(), t!("functions.secret.secretNotFound", name = secret_name).to_string())) |
| 74 | } |
| 75 | } |
| 76 | } |
| 77 | |
| 78 | #[cfg(test)] |