ExampleΒΆ
Here is a provider built using this framework that hashes a string using MD5.
While this provider does not talk to a remote server, it demonstrates how to use the framework to build a provider.
from typing import Optional, Type
import hashlib
from tf import schema, types
from tf.schema import Attribute, Schema
from tf.iface import Config, DataSource, Resource, State, CreateContext, ReadContext, UpdateContext, DeleteContext
from tf.provider import Provider
from tf.runner import run_provider
from tf.utils import Diagnostics
class HasherProvider(Provider):
def __init__(self):
self.salt = b""
def get_model_prefix(self) -> str:
return "hasher_"
def full_name(self) -> str:
return "tf.example.com/hasher/hasher"
def get_provider_schema(self, diags: Diagnostics) -> schema.Schema:
return schema.Schema(
version=1,
attributes=[
Attribute("salt", types.String(), required=True),
]
)
def validate_config(self, diags: Diagnostics, config: Config):
if len(config["salt"]) < 8:
diags.add_error("salt", "Salt must be at least 8 characters long")
def configure_provider(self, diags: Diagnostics, config: Config):
self.salt = config["salt"].encode()
def get_data_sources(self) -> list[Type[DataSource]]:
return []
def get_resources(self) -> list[Type[Resource]]:
return [Md5HashResource]
class Md5HashResource(Resource):
def __init__(self, provider: HasherProvider):
self.provider = provider
@classmethod
def get_name(cls) -> str:
return "md5_hash"
@classmethod
def get_schema(cls) -> Schema:
return Schema(
attributes=[
Attribute("input", types.String(), required=True),
Attribute("output", types.String(), computed=True),
]
)
def create(self, ctx: CreateContext, planned_state: State) -> State:
return {
"input": planned_state["input"],
"output": hashlib.md5(self.provider.salt + planned_state["input"].encode()).hexdigest()
}
def read(self, ctx: ReadContext, current_state: State) -> State:
# Normally we would have to talk to a remove server, but this is local
return {"input": current_state["input"], "output": current_state["output"]}
def update(self, ctx: UpdateContext, current_state: State, planned_state: State) -> State:
return {
"input": planned_state["input"],
"output": hashlib.md5(self.provider.salt + planned_state["input"].encode()).hexdigest()
}
def delete(self, ctx: DeleteContext, current_state: State) -> Optional[State]:
return None
if __name__ == "__main__":
provider = HasherProvider()
run_provider(provider)
Then we could consume this in Terraform like so:
provider "hasher" {
salt = "123456789"
}
resource "hasher_md5_hash" "myhash" {
input = "hello"
}
output "hash" {
value = hasher_md5_hash.myhash.output
}