support simple types

This commit is contained in:
nora 2024-04-10 21:48:30 +02:00
parent 69daf83c53
commit 18a9d610cd
7 changed files with 173 additions and 20 deletions

33
Cargo.lock generated
View file

@ -155,6 +155,12 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "bytes"
version = "1.6.0"
@ -536,6 +542,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "num-traits"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.16.0"
@ -590,6 +605,12 @@ dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "paste"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
[[package]]
name = "pem"
version = "3.0.4"
@ -837,6 +858,17 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "rmp"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9860a6cc38ed1da53456442089b4dfa35e7cedaa326df63017af88385e6b20"
dependencies = [
"byteorder",
"num-traits",
"paste",
]
[[package]]
name = "rustc-demangle"
version = "0.1.23"
@ -1036,6 +1068,7 @@ dependencies = [
"eyre",
"prost",
"rcgen",
"rmp",
"rustls 0.23.4",
"tempfile",
"time",

View file

@ -3,11 +3,16 @@ name = "terraform-provider-terustform"
version = "0.1.0"
edition = "2021"
[profile.dev]
opt-level = 1
panic = "abort"
[dependencies]
base64 = "0.22.0"
eyre = "0.6.12"
prost = "0.12.4"
rcgen = "0.13.1"
rmp = "0.8.12"
rustls = { version = "0.23.4", default-features = false, features = ["ring", "logging", "std", "tls12"] }
tempfile = "3.10.1"
time = "0.3.35"

View file

@ -1,8 +0,0 @@
#!/usr/bin/env bash
echo "use nix" > .envrc
cat > shell.nix <<EOF
{ pkgs ? import <nixpkgs> {} }: pkgs.mkShell {
packages = [];
}
EOF

View file

@ -1,5 +1,6 @@
mod cert;
mod server;
mod values;
use std::{env, path::PathBuf};
@ -36,7 +37,6 @@ async fn main() -> eyre::Result<()> {
.client_auth_optional(true) // ??? terraform doesn't send certs ???
.client_ca_root(client_cert);
info!("Listening on {}", socket.display());
let uds = UnixListener::bind(socket).wrap_err("failed to bind unix listener")?;

View file

@ -4,12 +4,17 @@ pub mod tfplugin6 {
tonic::include_proto!("tfplugin6");
}
use std::{collections::HashMap, vec};
use std::{
collections::{BTreeMap, HashMap},
vec,
};
use tfplugin6::provider_server::{Provider, ProviderServer};
use tonic::{transport::Server, Request, Response, Result, Status};
use tracing::info;
use crate::values::Type;
#[derive(Debug, Default)]
pub struct MyProvider;
@ -57,7 +62,31 @@ impl Provider for MyProvider {
get_provider_schema_optional: true,
move_resource_state: false,
}),
data_source_schemas: HashMap::default(),
data_source_schemas: HashMap::from([(
"terustform_kitty".to_owned(),
tfplugin6::Schema {
version: 1,
block: Some(tfplugin6::schema::Block {
version: 0,
attributes: vec![tfplugin6::schema::Attribute {
name: "kitten".to_owned(),
r#type: Type::String.to_json().into_bytes(),
nested_type: None,
description: "what sound does the kitten make?".to_owned(),
required: false,
optional: false,
computed: true,
sensitive: false,
description_kind: 0,
deprecated: false,
}],
block_types: vec![],
description: "something or nothing?".to_owned(),
description_kind: 0,
deprecated: false,
}),
},
)]),
resource_schemas: HashMap::from([("terustform_hello".to_owned(), empty_schema())]),
functions: HashMap::default(),
diagnostics: vec![],
@ -93,8 +122,13 @@ impl Provider for MyProvider {
&self,
request: Request<tfplugin6::validate_data_resource_config::Request>,
) -> Result<Response<tfplugin6::validate_data_resource_config::Response>, Status> {
tracing::error!("validate_data_resource_config");
todo!("validate_data_resource_config")
tracing::info!("validate_data_resource_config");
let reply = tfplugin6::validate_data_resource_config::Response {
diagnostics: vec![],
};
Ok(Response::new(reply))
}
async fn upgrade_resource_state(
&self,
@ -126,10 +160,10 @@ impl Provider for MyProvider {
&self,
request: Request<tfplugin6::plan_resource_change::Request>,
) -> Result<Response<tfplugin6::plan_resource_change::Response>, Status> {
tracing::error!("plan_resource_change");
tracing::info!("plan_resource_change");
let reply = tfplugin6::plan_resource_change::Response {
planned_state: todo!(),
planned_state: request.into_inner().proposed_new_state,
requires_replace: vec![],
planned_private: vec![],
diagnostics: vec![],
@ -137,15 +171,22 @@ impl Provider for MyProvider {
deferred: None,
};
todo!("plan_resource_change")
Ok(Response::new(reply))
}
async fn apply_resource_change(
&self,
request: Request<tfplugin6::apply_resource_change::Request>,
) -> Result<Response<tfplugin6::apply_resource_change::Response>, Status> {
tracing::error!("apply_resource_change");
tracing::info!("apply_resource_change");
todo!("apply_resource_change")
let reply = tfplugin6::apply_resource_change::Response {
new_state: request.into_inner().planned_state,
private: vec![],
diagnostics: vec![],
legacy_type_system: false,
};
Ok(Response::new(reply))
}
async fn import_resource_state(
&self,
@ -169,7 +210,22 @@ impl Provider for MyProvider {
) -> Result<Response<tfplugin6::read_data_source::Response>, Status> {
tracing::error!("read_data_source");
todo!("read_data_source")
let reply = tfplugin6::read_data_source::Response {
state: Some(tfplugin6::DynamicValue {
msgpack: crate::values::Value::Object(BTreeMap::from([(
"kitten".to_owned(),
Box::new(crate::values::Value::String("meow".to_owned())),
)]))
.msg_pack(),
json: vec![],
}),
deferred: None,
diagnostics: vec![],
};
dbg!(request);
Ok(Response::new(reply))
}
/// GetFunctions returns the definitions of all functions.
async fn get_functions(

61
src/values.rs Normal file
View file

@ -0,0 +1,61 @@
// check terraform-plugin-go tfprotov6/internal/toproto for convesions
// tftypes for types and values
use std::collections::{BTreeMap, HashMap};
pub enum Type {
Number,
String,
}
impl Type {
pub fn to_json(&self) -> String {
match *self {
Self::String => "\"string\"".to_owned(),
Self::Number => "\"number\"".to_owned(),
}
}
}
pub struct DynamicValue {
msgpack: Option<Vec<u8>>,
json: Option<Vec<u8>>,
}
// this is very dumb and wrong
pub enum Value {
String(String),
Object(BTreeMap<String, Box<Value>>)
}
impl Value {
pub fn ty(&self) -> Type {
todo!()
}
}
// marshal msg pack
// tftypes/value.go:MarshalMsgPack
impl Value {
pub fn msg_pack(&self) -> Vec<u8> {
let mut buf = Vec::new();
self.msg_pack_inner(&mut buf);
buf
}
pub fn msg_pack_inner(&self, v: &mut Vec<u8>) {
match self {
Value::String(s) => {
rmp::encode::write_str(v, s).unwrap();
}
Value::Object(o) => {
rmp::encode::write_map_len(v, o.len().try_into().unwrap()).unwrap();
for (key, val) in o {
rmp::encode::write_str(v, key).unwrap();
val.msg_pack_inner(v);
}
}
}
}
}

View file

@ -8,4 +8,10 @@ terraform {
provider "terustform" {}
resource "terustform_hello" "test1" {}
//resource "terustform_hello" "test1" {}
data "terustform_kitty" "kitty" {}
output "meow" {
value = data.terustform_kitty.kitty.kitten
}