From 3c891034ee98858134aa65261eb2201feb2e03eb Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 21 Apr 2024 13:30:25 +0200 Subject: [PATCH] Implement class data source --- terraform-provider-corsschool/src/client.rs | 30 ++++-- terraform-provider-corsschool/src/main.rs | 1 + .../src/resources/class_data_source.rs | 92 +++++++++++++++++++ .../src/resources/hugo.rs | 15 +-- .../src/resources/mod.rs | 3 +- terraform-provider-corsschool/test/main.tf | 7 ++ terustform/src/values.rs | 15 +++ 7 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 terraform-provider-corsschool/src/resources/class_data_source.rs diff --git a/terraform-provider-corsschool/src/client.rs b/terraform-provider-corsschool/src/client.rs index 580db74..25d2603 100644 --- a/terraform-provider-corsschool/src/client.rs +++ b/terraform-provider-corsschool/src/client.rs @@ -1,5 +1,8 @@ use eyre::{Context, OptionExt, Result}; -use reqwest::header::{HeaderMap, HeaderValue}; +use reqwest::{ + header::{HeaderMap, HeaderValue}, + RequestBuilder, Response, +}; #[derive(Clone)] pub struct CorsClient { @@ -29,7 +32,7 @@ impl CorsClient { let mut headers = HeaderMap::new(); headers.insert( "Authorization", - HeaderValue::from_str(&format!("Bearer {}", token,)).unwrap(), + HeaderValue::from_str(token).unwrap(), ); let client = reqwest::Client::builder() .default_headers(headers) @@ -40,12 +43,27 @@ impl CorsClient { } pub async fn get_hugo(&self) -> Result { - Ok(self - .client - .get(format!("{URL}/hugo")) - .send() + Ok(do_request(self.client.get(format!("{URL}/hugo"))) .await? .text() .await?) } + + pub async fn get_class(&self, id: &str) -> Result { + Ok(do_request(self.client.get(format!("{URL}/classes/{id}"))) + .await? + .json() + .await?) + } +} + +async fn do_request(req: RequestBuilder) -> Result { + dbg!(&req); + let res = req.send().await?; + if let Err(err) = res.error_for_status_ref() { + let text = res.text().await.unwrap_or_default(); + return Err(err).wrap_err(text); + } + + Ok(res.error_for_status().wrap_err("failed to get class")?) } diff --git a/terraform-provider-corsschool/src/main.rs b/terraform-provider-corsschool/src/main.rs index b288d2d..4164b9a 100644 --- a/terraform-provider-corsschool/src/main.rs +++ b/terraform-provider-corsschool/src/main.rs @@ -48,6 +48,7 @@ impl Provider for ExampleProvider { vec![ resources::kitty::ExampleDataSource::erase(), resources::hugo::HugoDataSource::erase(), + resources::class_data_source::ClassDataSource::erase(), ] } } diff --git a/terraform-provider-corsschool/src/resources/class_data_source.rs b/terraform-provider-corsschool/src/resources/class_data_source.rs new file mode 100644 index 0000000..70bd832 --- /dev/null +++ b/terraform-provider-corsschool/src/resources/class_data_source.rs @@ -0,0 +1,92 @@ +use std::collections::HashMap; + +use eyre::Context; +use terustform::{ + datasource::DataSource, AttrPath, Attribute, DResult, EyreExt, Mode, Schema, StringValue, + Value, ValueModel, +}; + +use crate::client::CorsClient; + +pub struct ClassDataSource { + client: CorsClient, +} + +#[derive(terustform::Model)] +struct ClassDataSourceModel { + id: StringValue, + name: StringValue, + description: StringValue, + discord_id: StringValue, +} + +#[terustform::async_trait] +impl DataSource for ClassDataSource { + type ProviderData = CorsClient; + + async fn read(&self, config: Value) -> DResult { + let mut model = ClassDataSourceModel::from_value(config, &AttrPath::root())?; + + let class = self + .client + .get_class(&model.id.expect_known(AttrPath::attr("id"))?) + .await + .wrap_err("failed to get class") + .eyre_to_tf()?; + + model.name = StringValue::Known(class.name); + model.description = StringValue::Known(class.description); + model.discord_id = StringValue::from(class.discord_id); + + Ok(model.to_value()) + } + + fn name(provider_name: &str) -> String { + format!("{provider_name}_class") + } + + fn schema() -> Schema { + Schema { + description: "Get a class by name".to_owned(), + attributes: HashMap::from([ + ( + "id".to_owned(), + // TODO: UUID validation :3 + Attribute::String { + description: "The UUID".to_owned(), + mode: Mode::Required, + sensitive: false, + }, + ), + ( + "name".to_owned(), + Attribute::String { + description: "The description".to_owned(), + mode: Mode::Computed, + sensitive: false, + }, + ), + ( + "description".to_owned(), + Attribute::String { + description: "The description".to_owned(), + mode: Mode::Computed, + sensitive: false, + }, + ), + ( + "discord_id".to_owned(), + Attribute::String { + description: "The discord ID of the class".to_owned(), + mode: Mode::Computed, + sensitive: false, + }, + ), + ]), + } + } + + fn new(data: Self::ProviderData) -> DResult { + Ok(Self { client: data }) + } +} diff --git a/terraform-provider-corsschool/src/resources/hugo.rs b/terraform-provider-corsschool/src/resources/hugo.rs index ca9ca84..f0d642a 100644 --- a/terraform-provider-corsschool/src/resources/hugo.rs +++ b/terraform-provider-corsschool/src/resources/hugo.rs @@ -35,17 +35,11 @@ impl DataSource for HugoDataSource { .to_value()) } - fn name(provider_name: &str) -> String - where - Self: Sized, - { + fn name(provider_name: &str) -> String { format!("{provider_name}_hugo") } - fn schema() -> Schema - where - Self: Sized, - { + fn schema() -> Schema { Schema { description: "Get Hugo Boss".to_owned(), attributes: HashMap::from([( @@ -59,10 +53,7 @@ impl DataSource for HugoDataSource { } } - fn new(data: Self::ProviderData) -> DResult - where - Self: Sized, - { + fn new(data: Self::ProviderData) -> DResult { Ok(Self { client: data }) } } diff --git a/terraform-provider-corsschool/src/resources/mod.rs b/terraform-provider-corsschool/src/resources/mod.rs index 86b8414..c1507f7 100644 --- a/terraform-provider-corsschool/src/resources/mod.rs +++ b/terraform-provider-corsschool/src/resources/mod.rs @@ -1,2 +1,3 @@ +pub mod class_data_source; pub mod hugo; -pub mod kitty; \ No newline at end of file +pub mod kitty; diff --git a/terraform-provider-corsschool/test/main.tf b/terraform-provider-corsschool/test/main.tf index dbf8358..ea1f3e1 100644 --- a/terraform-provider-corsschool/test/main.tf +++ b/terraform-provider-corsschool/test/main.tf @@ -26,4 +26,11 @@ output "cat2" { data "corsschool_hugo" "hugo" {} output "hugo" { value = data.corsschool_hugo.hugo +} + +data "corsschool_class" "test" { + id = "f245514b-f99c-4c09-ab53-eabd944af6d2" +} +output "class" { + value = data.corsschool_class.test } \ No newline at end of file diff --git a/terustform/src/values.rs b/terustform/src/values.rs index 63171d8..55bd042 100644 --- a/terustform/src/values.rs +++ b/terustform/src/values.rs @@ -146,6 +146,21 @@ impl BaseValue { } } +impl From for BaseValue { + fn from(value: T) -> Self { + Self::Known(value) + } +} + +impl From> for BaseValue { + fn from(value: Option) -> Self { + match value { + Some(value) => Self::Known(value), + None => Self::Null, + } + } +} + pub trait ValueModel: Sized { fn from_value(v: Value, path: &AttrPath) -> DResult;