aws_parameter_update/lib.rs
1//! # AWS Parameter Update Library
2//!
3//! `aws_parameter_update` is a small tool used to quickly update simple AWS Parameters
4#![warn(missing_docs)]
5#![warn(missing_doc_code_examples)]
6
7use anyhow::Result;
8use log::{error, info};
9use rusoto_core::Region;
10use rusoto_ssm::SsmClient;
11use std::fs::File;
12use std::io::prelude::Read;
13use std::iter::Map;
14use yaml_rust::YamlLoader;
15
16pub use parameter::Parameter;
17
18mod parameter;
19/// Updates AWS Parameters from a YAML file
20///
21/// # File Structure
22/// The file structure for updating parameters is as follows:
23/// ```yaml
24/// - name: "new_parameter"
25/// value: "Example parameter"
26/// description: "An example of an unsecure parameter"
27/// is_secure: false
28/// - name: "new_secure_parameter"
29/// value: "$uper$ecretP@$$W0rd"
30/// description: "An example of a secure parameter"
31/// is_secure: true
32/// ```
33///
34/// # Example
35///
36/// ```should_panic because there is no file
37/// let filename = "non_existing_file.yaml";
38///
39/// match tokio_test::block_on(aws_parameter_update::update_from_file(filename)) {
40/// Ok(_) => {
41/// println!("Parameter update from file {} finished", filename);
42/// }
43/// Err(error) => {
44/// println!("Parameter updated from file {} failed: {}", filename, error);
45/// }
46/// };
47/// ```
48pub async fn update_from_file(filename: &str) -> Result<()> {
49 let parameters_from_yaml = read_parameters_yaml(filename)?;
50
51 update_parameters(parameters_from_yaml).await
52}
53
54/// Updates AWS Parameter from calling function input
55///
56/// # Example
57///
58/// ```
59/// let name = "name".to_string();
60/// let value = "value".to_string();
61/// let description = "description".to_string();
62/// let is_secure = true;
63///
64/// match tokio_test::block_on(aws_parameter_update::update_parameter(&name, &value, &description, is_secure)) {
65/// Ok(_) => {
66/// println!("Parameter update finished");
67/// }
68/// Err(error) => {
69/// println!("Parameter update failed: {}", error);
70/// }
71/// };
72/// ```
73pub async fn update_parameter(
74 name: &str,
75 value: &str,
76 description: &str,
77 is_secure: bool,
78) -> Result<()> {
79 update_parameters(vec![Parameter::new(name, value, description, is_secure)]).await
80}
81
82/// Updates AWS Parameters from calling function input
83///
84/// # Example
85///
86/// ```
87/// use aws_parameter_update::Parameter;
88///
89/// let parameters_to_update = vec![Parameter::new(
90/// "firstName",
91/// "firstValue",
92/// "firstDescription",
93/// true,
94/// ),
95/// Parameter::new(
96/// "secondName",
97/// "secondValue",
98/// "secondDescription",
99/// false,
100/// )];
101///
102/// match tokio_test::block_on(aws_parameter_update::update_parameters(parameters_to_update)) {
103/// Ok(_) => {
104/// println!("Parameter updates finished");
105/// }
106/// Err(error) => {
107/// println!("Parameter updates failed: {}", error);
108/// }
109/// };
110/// ```
111pub async fn update_parameters(parameters: Vec<Parameter>) -> Result<()> {
112 let client = SsmClient::new(Region::UsWest2);
113
114 for parameter in parameters {
115 match parameter.update(&client).await {
116 Ok(parameter_name) => info!("Parameter {} processed", parameter_name),
117 Err(_error) => error!("Parameter not updated"),
118 }
119 }
120
121 info!("Parameter update finished running");
122 Ok(())
123}
124
125fn read_parameters_yaml(filename: &str) -> Result<Vec<Parameter>> {
126 let mut file = File::open(filename).expect("Unable to open parameter input file");
127 let mut contents = String::new();
128
129 file.read_to_string(&mut contents)
130 .expect("Unable to read parameter input file");
131
132 // YamlLoader returns a "doc" which can have multiple YAML files in it,
133 // hence the two iterators and the flattening
134 let parameters = YamlLoader::load_from_str(&contents)?
135 .into_iter()
136 .map(|yaml_document| -> Map<_, _> {
137 yaml_document.into_iter().map(|param| -> Parameter {
138 Parameter::new(
139 param["name"].as_str().expect("name missing"),
140 param["value"].as_str().expect("value missing"),
141 param["description"].as_str().expect("description missing"),
142 param["is_secure"].as_bool().expect("is_secure missing"),
143 )
144 })
145 })
146 .flatten()
147 .collect::<Vec<_>>();
148
149 info!("Parameters YAML loaded");
150 Ok(parameters)
151}
152
153mod tests {
154 #[tokio::test]
155 #[should_panic]
156 async fn test_update_from_file() {
157 let result = crate::update_from_file("missing_file.yaml").await;
158
159 assert!(result.is_err());
160 }
161
162 #[tokio::test]
163 async fn test_update_parameter() {
164 let result = crate::update_parameter("name", "value", "description", true).await;
165
166 assert!(result.is_ok());
167 }
168
169 #[tokio::test]
170 async fn test_update_parameters() {
171 let result = crate::update_parameters(vec![crate::Parameter::new(
172 "name",
173 "value",
174 "description",
175 true,
176 )])
177 .await;
178
179 assert!(result.is_ok());
180 }
181}