Skip to content

Commit

Permalink
chore: docs (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
lemaitre-aneo authored Jun 16, 2024
2 parents 27b2e3d + fd575df commit 15e10d7
Show file tree
Hide file tree
Showing 18 changed files with 1,730 additions and 66 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
authors = ["Florian Lemaitre <[email protected]>"]
description = "Plugin framework for Terraform and ToFu"
edition = "2021"
include = ["**/*.rs", "Cargo.toml", "LICENSE", "proto/*.proto"]
include = ["**/*.rs", "Cargo.toml", "LICENSE", "README.md", "proto/*.proto"]
license = "Apache-2.0"
readme = "README.md"
name = "tf-provider"
repository = "https://github.com/aneoconsulting/tf-provider"
version = "0.2.0-beta-0"
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# TF-PROVIDER

[![Crates.io License](https://img.shields.io/crates/l/tf-provider)](https://crates.io/crates/tf-provider)
[![Crates.io Version](https://img.shields.io/crates/v/tf-provider)](https://crates.io/crates/tf-provider)
[![docs.rs](https://img.shields.io/docsrs/tf-provider)](https://docs.rs/tf-provider/)
[![Build status](https://img.shields.io/github/check-runs/aneoconsulting/tf-provider/main)](https://github.com/aneoconsulting/tf-provider)



Terraform provider library

It enables to write your own TF provider that is supported by both Terraform and OpenTofu.

Links:
- [github](https://github.com/aneoconsulting/tf-provider)
- [crates](https://crates.io/crates/tf-provider)
- [docs](https://docs.rs/tf-provider/)
12 changes: 5 additions & 7 deletions examples/terraform-provider-fn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ use anyhow::Result;
use async_trait::async_trait;

use serde::{Deserialize, Serialize};
use tf_provider::schema::{FunctionSchema, Parameter, Type};
use tf_provider::{
map, serve, Block, Description, Diagnostics, Function, Provider, Schema, ValueEmpty,
};
use tf_provider::schema::{Block, Description, FunctionSchema, Parameter, Schema, Type};
use tf_provider::value::ValueEmpty;
use tf_provider::{map, serve, Diagnostics, Function, Provider};

#[derive(Debug, Default, Clone, Copy)]
pub struct Add;
Expand Down Expand Up @@ -77,7 +76,7 @@ impl Provider for FnProvider {
type Config<'a> = ValueEmpty;
type MetaState<'a> = ValueEmpty;

fn schema(&self, _diags: &mut tf_provider::Diagnostics) -> Option<tf_provider::Schema> {
fn schema(&self, _diags: &mut tf_provider::Diagnostics) -> Option<tf_provider::schema::Schema> {
Some(Schema {
version: 1,
block: Block {
Expand All @@ -90,8 +89,7 @@ impl Provider for FnProvider {
fn get_functions(
&self,
_diags: &mut tf_provider::Diagnostics,
) -> Option<std::collections::HashMap<String, Box<dyn tf_provider::function::DynamicFunction>>>
{
) -> Option<std::collections::HashMap<String, Box<dyn tf_provider::DynamicFunction>>> {
Some(map! {
"add" => Add,
})
Expand Down
18 changes: 8 additions & 10 deletions examples/terraform-provider-null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use serde::{Deserialize, Serialize};

use tf_provider::{
map, serve, Attribute, AttributeConstraint, AttributePath, AttributeType, Block, Description,
Diagnostics, Provider, Resource, Schema, ValueEmpty, ValueMap, ValueString,
use tf_provider::schema::{
Attribute, AttributeConstraint, AttributeType, Block, Description, Schema,
};
use tf_provider::value::{ValueEmpty, ValueMap, ValueString};
use tf_provider::{map, serve, AttributePath, Diagnostics, Provider, Resource};

#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct NullState<'a> {
Expand Down Expand Up @@ -105,7 +106,7 @@ impl Resource for NullResource {
) -> Option<(
Self::State<'a>,
Self::PrivateState<'a>,
Vec<tf_provider::attribute_path::AttributePath>,
Vec<tf_provider::AttributePath>,
)> {
let mut trigger_replace = Vec::new();
if proposed_state.triggers != prior_state.triggers {
Expand Down Expand Up @@ -174,7 +175,7 @@ impl Provider for NullProvider {
type Config<'a> = ValueEmpty;
type MetaState<'a> = ValueEmpty;

fn schema(&self, _diags: &mut tf_provider::Diagnostics) -> Option<tf_provider::Schema> {
fn schema(&self, _diags: &mut tf_provider::Diagnostics) -> Option<tf_provider::schema::Schema> {
Some(Schema {
version: 1,
block: Block {
Expand Down Expand Up @@ -204,8 +205,7 @@ impl Provider for NullProvider {
fn get_resources(
&self,
_diags: &mut tf_provider::Diagnostics,
) -> Option<std::collections::HashMap<String, Box<dyn tf_provider::resource::DynamicResource>>>
{
) -> Option<std::collections::HashMap<String, Box<dyn tf_provider::DynamicResource>>> {
Some(map! {
"resource" => NullResource,
})
Expand All @@ -214,9 +214,7 @@ impl Provider for NullProvider {
fn get_data_sources(
&self,
_diags: &mut tf_provider::Diagnostics,
) -> Option<
std::collections::HashMap<String, Box<dyn tf_provider::data_source::DynamicDataSource>>,
> {
) -> Option<std::collections::HashMap<String, Box<dyn tf_provider::DynamicDataSource>>> {
Some(map! {})
}
}
Expand Down
56 changes: 55 additions & 1 deletion src/attribute_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,66 +14,116 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! [`AttributePath`] module
use std::{borrow::Cow, fmt::Display};

use crate::tfplugin6;

/// Represent the path to an attribute
///
/// # Example
///
/// ```
/// # use tf_provider::AttributePath;
/// let path = AttributePath::new("foo").key("bar").attribute("array").index(1);
/// // foo["bar"].array[1]
/// ```
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
pub struct AttributePath {
pub steps: Vec<AttributePathStep>,
}

impl AttributePath {
/// Create a new attribute path with the `root` attribute
///
/// # Arguments
///
/// * `root` - Name of the root attribute
pub fn new<T: Into<Cow<'static, str>>>(root: T) -> Self {
Self {
steps: vec![AttributePathStep::Attribute(root.into())],
}
}
/// Create a new attribute path for a function argument
///
/// # Arguments
///
/// * `index` - index of the function argument
pub fn function_argument(index: i64) -> Self {
Self {
steps: vec![AttributePathStep::Index(index)],
}
}
/// Create a new attribute path where the attribute `.name` has been appended
///
/// # Arguments
///
/// * `name` - name of the attribute
pub fn attribute<T: Into<Cow<'static, str>>>(mut self, name: T) -> Self {
self.add_attribute(name);
self
}
/// Create a new attribute path where the access `["key"]` has been appended
///
/// # Arguments
///
/// * `key` - string subscript
pub fn key<T: Into<Cow<'static, str>>>(mut self, key: T) -> Self {
self.add_key(key);
self
}
/// Create a new attribute path where the access `[idx]` has been appended
///
/// # Arguments
///
/// * `idx` - integer subscript
pub fn index<T: Into<i64>>(mut self, idx: T) -> Self {
self.add_index(idx);
self
}

/// add name access to the path (ie: `.name`)
/// Add name access to the path (ie: `.name`)
///
/// # Arguments
///
/// * `name` - name of the attribute
pub fn add_attribute<T: Into<Cow<'static, str>>>(&mut self, name: T) -> &mut Self {
self.steps.push(AttributePathStep::Attribute(name.into()));
self
}
/// add key access to the path (ie: `["key"]`)
///
/// # Arguments
///
/// * `key` - string subscript
pub fn add_key<T: Into<Cow<'static, str>>>(&mut self, key: T) -> &mut Self {
self.steps.push(AttributePathStep::Key(key.into()));
self
}
/// add index access to the path (ie: `[idx]`)
///
/// # Arguments
///
/// * `idx` - integer subscript
pub fn add_index<T: Into<i64>>(&mut self, idx: T) -> &mut Self {
self.steps.push(AttributePathStep::Index(idx.into()));
self
}
/// Add step to the path
///
/// # Arguments
///
/// * `step` - step to add
pub fn add_step(&mut self, step: AttributePathStep) -> &mut Self {
self.steps.push(step);
self
}
/// Add multiple steps into the path
///
/// # Arguments
///
/// * `steps` - steps to add
pub fn add_steps(&mut self, mut steps: AttributePath) -> &mut Self {
self.steps.append(&mut steps.steps);
self
Expand Down Expand Up @@ -125,10 +175,14 @@ impl From<AttributePath> for tfplugin6::AttributePath {
}
}

/// Single step of an [`AttributePath`]
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum AttributePathStep {
/// Attribute access: `.foo`
Attribute(Cow<'static, str>),
/// String subscript: `["foo"]`
Key(Cow<'static, str>),
/// Integer subscript: `[1]`
Index(i64),
}

Expand Down
80 changes: 78 additions & 2 deletions src/data_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! [`DataSource`] module
use crate::diagnostics::Diagnostics;
use crate::raw::RawValue;
use crate::schema::Schema;
Expand All @@ -23,22 +25,61 @@ use async_trait::async_trait;
use serde::{Deserialize, Serialize};

#[async_trait]
/// Trait for implementing a data source
/// Trait for implementing a data source with automatic serialization/deserialization
///
/// See also: [`DynamicDataSource`]
pub trait DataSource: Send + Sync {
/// State of the data source
///
/// The state will be automatically serialized/deserialized at the border of the request.
type State<'a>: Serialize + Deserialize<'a> + Send;

/// State of the provider metadata
///
/// The state will be automatically serialized/deserialized at the border of the request.
type ProviderMetaState<'a>: Serialize + Deserialize<'a> + Send;

/// Get the schema of the data source
///
/// # Arguments
///
/// * `diags` - Diagnostics to record warnings and errors that occured when getting back the schema
///
/// # Remarks
///
/// The return is ignored if there is an error in diagnostics.
/// If the return is [`None`], an ad-hoc error is added to diagnostics.
fn schema(&self, diags: &mut Diagnostics) -> Option<Schema>;

/// Validate the configuration of the data source
///
/// # Arguments
///
/// * `diags` - Diagnostics to record warnings and errors that occured during validation
/// * `config` - State as declared in the Terraform file
///
/// # Remarks
///
/// The return is ignored if there is an error in diagnostics.
/// If the return is [`None`], an ad-hoc error is added to diagnostics.
async fn validate<'a>(&self, diags: &mut Diagnostics, config: Self::State<'a>) -> Option<()> {
_ = diags;
_ = config;
Some(())
}
/// Read the new state of the data source

/// Read the state of the data source
///
/// # Arguments
///
/// * `diags` - Diagnostics to record warnings and errors that occured during the read
/// * `config` - State as declared in the Terraform file
/// * `provider_meta_state` - State of the provider metadata as declared in the Terraform file
///
/// # Remarks
///
/// The return is ignored if there is an error in diagnostics.
/// If the return is [`None`], an ad-hoc error is added to diagnostics.
async fn read<'a>(
&self,
diags: &mut Diagnostics,
Expand All @@ -48,16 +89,51 @@ pub trait DataSource: Send + Sync {
}

#[async_trait]
/// Trait for implementing a data source *without* automatic serialization/deserialization
///
/// See also: [`DataSource`]
pub trait DynamicDataSource: Send + Sync {
/// Get the schema of the data source
///
/// # Arguments
///
/// * `diags` - Diagnostics to record warnings and errors that occured when getting back the schema
///
/// # Remarks
///
/// The return is ignored if there is an error in diagnostics.
/// If the return is [`None`], an ad-hoc error is added to diagnostics.
fn schema(&self, diags: &mut Diagnostics) -> Option<Schema>;

/// Validate the configuration of the data source
///
/// # Arguments
///
/// * `diags` - Diagnostics to record warnings and errors that occured during validation
/// * `config` - State as declared in the Terraform file
///
/// # Remarks
///
/// The return is ignored if there is an error in diagnostics.
/// If the return is [`None`], an ad-hoc error is added to diagnostics.
async fn validate(&self, diags: &mut Diagnostics, config: RawValue) -> Option<()> {
_ = diags;
_ = config;
Some(())
}

/// Read the new state of the data source
///
/// # Arguments
///
/// * `diags` - Diagnostics to record warnings and errors that occured during the read
/// * `config` - State as declared in the Terraform file
/// * `provider_meta_state` - State of the provider metadata as declared in the Terraform file
///
/// # Remarks
///
/// The return is ignored if there is an error in diagnostics.
/// If the return is [`None`], an ad-hoc error is added to diagnostics.
async fn read(
&self,
diags: &mut Diagnostics,
Expand Down
Loading

0 comments on commit 15e10d7

Please sign in to comment.