From 69daf83c53d4b574233e2cd37371c35c217fd3d7 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 10 Apr 2024 20:57:16 +0200 Subject: [PATCH] continue --- .gitignore | 1 + Cargo.lock | 222 +++++++++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 9 +- src/cert.rs | 29 +++++++ src/main.rs | 75 +++++++++++------ src/server.rs | 193 ++++++++++++++++++++++++++++--------------- test/main.tf | 4 + 7 files changed, 442 insertions(+), 91 deletions(-) create mode 100644 src/cert.rs diff --git a/.gitignore b/.gitignore index ea8c4bf..f693352 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +*.tfstate* diff --git a/Cargo.lock b/Cargo.lock index 593a638..a9f1458 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,6 +137,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" + [[package]] name = "bitflags" version = "1.3.2" @@ -167,6 +173,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + [[package]] name = "either" version = "1.10.0" @@ -427,6 +442,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.153" @@ -499,6 +520,22 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num_cpus" version = "1.16.0" @@ -524,6 +561,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "parking_lot" version = "0.12.1" @@ -547,6 +590,16 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.0", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -595,6 +648,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -712,6 +771,19 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rcgen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54077e1872c46788540de1ea3d7f4ccb1983d12f9aa909b234468676c1a36779" +dependencies = [ + "pem", + "ring", + "rustls-pki-types", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -784,6 +856,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99008d7ad0bbbea527ec27bddbc0e432c5b87d8175178cee68d2eec9c4a1813c" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + [[package]] name = "rustls" version = "0.23.4" @@ -799,6 +885,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64 0.22.0", + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.4.1" @@ -848,6 +944,15 @@ dependencies = [ "syn", ] +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -927,14 +1032,50 @@ dependencies = [ name = "terraform-provider-terustform" version = "0.1.0" dependencies = [ + "base64 0.22.0", "eyre", "prost", - "rustls", + "rcgen", + "rustls 0.23.4", + "tempfile", + "time", "tokio", + "tokio-stream", "tonic", "tonic-build", + "tracing", + "tracing-subscriber", ] +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef89ece63debf11bc32d1ed8d078ac870cbeb44da02afb02a9ff135ae7ca0582" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tokio" version = "1.37.0" @@ -975,6 +1116,17 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.3", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.15" @@ -1009,7 +1161,7 @@ dependencies = [ "async-stream", "async-trait", "axum", - "base64", + "base64 0.21.7", "bytes", "h2", "http", @@ -1019,7 +1171,10 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-pemfile", + "rustls-pki-types", "tokio", + "tokio-rustls", "tokio-stream", "tower", "tower-layer", @@ -1101,6 +1256,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", ] [[package]] @@ -1121,6 +1302,12 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "want" version = "0.3.1" @@ -1136,6 +1323,28 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-sys" version = "0.48.0" @@ -1268,6 +1477,15 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/Cargo.toml b/Cargo.toml index 3bef4f1..b0cbd15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,11 +4,18 @@ version = "0.1.0" edition = "2021" [dependencies] +base64 = "0.22.0" eyre = "0.6.12" prost = "0.12.4" +rcgen = "0.13.1" rustls = { version = "0.23.4", default-features = false, features = ["ring", "logging", "std", "tls12"] } +tempfile = "3.10.1" +time = "0.3.35" tokio = { version = "1.37.0", features = ["full"] } -tonic = "0.11.0" +tokio-stream = { version = "0.1.15", features = ["net"] } +tonic = { version = "0.11.0", features = ["tls"] } +tracing = "0.1.40" +tracing-subscriber = "0.3.18" [build-dependencies] tonic-build = "0.11.0" diff --git a/src/cert.rs b/src/cert.rs new file mode 100644 index 0000000..3f27ee5 --- /dev/null +++ b/src/cert.rs @@ -0,0 +1,29 @@ +use eyre::{Context, Result}; +use rcgen::{DistinguishedName, DnType, IsCa, KeyUsagePurpose}; +use time::Duration; + +pub fn generate_cert() -> Result<(tonic::transport::Identity, rcgen::Certificate)> { + // https://github.com/hashicorp/go-plugin/blob/8d2aaa458971cba97c3bfec1b0380322e024b514/mtls.go#L20 + let keypair = rcgen::KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256) + .wrap_err("failed to generate keypair")?; + + let mut params = + rcgen::CertificateParams::new(["localhost".to_owned()]).wrap_err("creating cert params")?; + params.key_usages = vec![ + KeyUsagePurpose::DigitalSignature, + KeyUsagePurpose::KeyEncipherment, + KeyUsagePurpose::KeyAgreement, + KeyUsagePurpose::KeyCertSign, + ]; + params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained); + params.not_before = time::OffsetDateTime::now_utc().saturating_add(Duration::seconds(-30)); + params.not_after = time::OffsetDateTime::now_utc().saturating_add(Duration::seconds(262980)); + let mut dn = DistinguishedName::new(); + dn.push(DnType::OrganizationName, "HashiCorp"); + dn.push(DnType::CommonName, "localhost"); + params.distinguished_name = dn; + + let cert = params.self_signed(&keypair).wrap_err("signing cert")?; + + Ok((tonic::transport::Identity::from_pem(cert.pem(), keypair.serialize_pem()), cert)) +} diff --git a/src/main.rs b/src/main.rs index 647e78b..3aecc8e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,18 +1,29 @@ -use std::{ - env, - io::Write, - net::{IpAddr, Ipv4Addr, SocketAddr}, -}; - -use eyre::{bail, ensure, Context, Result}; - +mod cert; mod server; +use std::{env, path::PathBuf}; + +use base64::Engine; +use eyre::{bail, Context, Result}; +use tokio::net::UnixListener; +use tonic::transport::{Certificate, ServerTlsConfig}; +use tracing::{info, Level}; + #[tokio::main] async fn main() -> eyre::Result<()> { - let addr = init_handshake(); + tracing_subscriber::fmt() + .with_max_level(Level::DEBUG) + .with_writer(std::io::stderr) + .without_time() + .init(); - let addr = match addr { + let client_cert = + std::env::var("PLUGIN_CLIENT_CERT").wrap_err("PLUGIN_CLIENT_CERT not found")?; + let client_cert = Certificate::from_pem(client_cert); + let (server_identity, server_cert) = + cert::generate_cert().wrap_err("generating server certificate")?; + + let (_tmpdir, socket) = match init_handshake(&server_cert).await { Ok(addr) => addr, Err(err) => { println!("{:?}", err); @@ -20,40 +31,58 @@ async fn main() -> eyre::Result<()> { } }; - let cert = std::env::var("PLUGIN_CLIENT_CERT").wrap_err("PLUGIN_CLIENT_CERT not found")?; + let tls = ServerTlsConfig::new() + .identity(server_identity) + .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")?; + let uds_stream = tokio_stream::wrappers::UnixListenerStream::new(uds); tonic::transport::Server::builder() + .tls_config(tls) + .wrap_err("invalid TLS config")? .add_service(server::tfplugin6::provider_server::ProviderServer::new( server::MyProvider, )) - .serve(addr) + .serve_with_incoming(uds_stream) .await .wrap_err("failed to start server")?; Ok(()) } -fn init_handshake() -> Result { +const _MAGIC_COOKIE_KEY: &str = "TF_PLUGIN_MAGIC_COOKIE"; +const _MAGIC_COOKIE_VALUE: &str = + "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2"; + +async fn init_handshake(server_cert: &rcgen::Certificate) -> Result<(tempfile::TempDir, PathBuf)> { // https://github.com/hashicorp/go-plugin/blob/8d2aaa458971cba97c3bfec1b0380322e024b514/docs/internals.md - let min_port = env::var("PLUGIN_MIN_PORT") + let _ = env::var("PLUGIN_MIN_PORT") .wrap_err("PLUGIN_MIN_PORT not found")? .parse::() .wrap_err("PLUGIN_MIN_PORT not an int")?; - let max_port = env::var("PLUGIN_MAX_PORT") + let _ = env::var("PLUGIN_MAX_PORT") .wrap_err("PLUGIN_MAX_PORT not found")? .parse::() .wrap_err("PLUGIN_MAX_PORT not an int")?; - let port = min_port + 15; // chosen by a d20, lol - ensure!(port < max_port); + let tmpdir = tempfile::TempDir::new().wrap_err("failed to create temporary directory")?; + let socket = tmpdir.path().join("plugin"); - let addr = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)); - let addr = SocketAddr::new(addr, port); + // https://github.com/hashicorp/go-plugin/blob/8d2aaa458971cba97c3bfec1b0380322e024b514/server.go#L426 + const CORE_PROTOCOL_VERSION: u8 = 1; + const PROTO_VERSION: u8 = 6; + let listener_addr_network = "unix"; + let listener_addr = socket.display(); + let proto_type = "grpc"; + let b64_cert = base64::prelude::BASE64_STANDARD_NO_PAD.encode(server_cert.der()); - const VERSION: u8 = 6; + println!("{CORE_PROTOCOL_VERSION}|{PROTO_VERSION}|{listener_addr_network}|{listener_addr}|{proto_type}|{b64_cert}"); - println!("1|{VERSION}|tcp|{addr}|grpc"); - - Ok(addr) + Ok((tmpdir, socket)) } diff --git a/src/server.rs b/src/server.rs index b27336c..8942c4c 100644 --- a/src/server.rs +++ b/src/server.rs @@ -1,13 +1,32 @@ +#![allow(unused_variables, unused_imports)] + pub mod tfplugin6 { tonic::include_proto!("tfplugin6"); } +use std::{collections::HashMap, vec}; + use tfplugin6::provider_server::{Provider, ProviderServer}; use tonic::{transport::Server, Request, Response, Result, Status}; +use tracing::info; #[derive(Debug, Default)] pub struct MyProvider; +fn empty_schema() -> tfplugin6::Schema { + tfplugin6::Schema { + version: 1, + block: Some(tfplugin6::schema::Block { + version: 0, + attributes: vec![], + block_types: vec![], + description: "hello world".to_owned(), + description_kind: 0, + deprecated: false, + }), + } +} + #[tonic::async_trait] impl Provider for MyProvider { /// GetMetadata returns upfront information about server capabilities and @@ -17,122 +36,166 @@ impl Provider for MyProvider { /// ignore the error and call the GetProviderSchema RPC as a fallback. async fn get_metadata( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { - todo!() + request: Request, + ) -> Result, Status> { + Err(Status::unimplemented( + "GetMetadata: Not implemeneted".to_owned(), + )) } /// GetSchema returns schema information for the provider, data resources, /// and managed resources. async fn get_provider_schema( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + info!("Received get_provider_schema"); + let reply = tfplugin6::get_provider_schema::Response { + provider: Some(empty_schema()), + provider_meta: Some(empty_schema()), + server_capabilities: Some(tfplugin6::ServerCapabilities { + plan_destroy: true, + get_provider_schema_optional: true, + move_resource_state: false, + }), + data_source_schemas: HashMap::default(), + resource_schemas: HashMap::from([("terustform_hello".to_owned(), empty_schema())]), + functions: HashMap::default(), + diagnostics: vec![], + }; + + Ok(Response::new(reply)) } async fn validate_provider_config( &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - todo!() + request: Request, + ) -> Result, Status> { + tracing::info!("validate_provider_config"); + + let reply = tfplugin6::validate_provider_config::Response { + diagnostics: vec![], + }; + + Ok(Response::new(reply)) } async fn validate_resource_config( &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - todo!() + request: Request, + ) -> Result, Status> { + tracing::info!("validate_resource_config"); + + let reply = tfplugin6::validate_resource_config::Response { + diagnostics: vec![], + }; + + Ok(Response::new(reply)) } async fn validate_data_resource_config( &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("validate_data_resource_config"); + todo!("validate_data_resource_config") } async fn upgrade_resource_state( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("upgrade_resource_state"); + todo!("upgrade_resource_state") } /// ////// One-time initialization, called before other functions below async fn configure_provider( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + tracing::info!("configure_provider"); + let reply = tfplugin6::configure_provider::Response { + diagnostics: vec![], + }; + Ok(Response::new(reply)) } /// ////// Managed Resource Lifecycle async fn read_resource( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("read_resource"); + todo!("read_resource") } async fn plan_resource_change( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("plan_resource_change"); + + let reply = tfplugin6::plan_resource_change::Response { + planned_state: todo!(), + requires_replace: vec![], + planned_private: vec![], + diagnostics: vec![], + legacy_type_system: false, + deferred: None, + }; + + todo!("plan_resource_change") } async fn apply_resource_change( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("apply_resource_change"); + + todo!("apply_resource_change") } async fn import_resource_state( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("import_resource_state"); + + todo!("import_resource_state") } async fn move_resource_state( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("move_resource_state"); + + todo!("move_resource_state") } async fn read_data_source( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> - { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("read_data_source"); + + todo!("read_data_source") } /// GetFunctions returns the definitions of all functions. async fn get_functions( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("get_functions"); + + todo!("get_functions") } /// ////// Provider-contributed Functions async fn call_function( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("call_function"); + + todo!("call_function") } /// ////// Graceful Shutdown async fn stop_provider( &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status> { - todo!() + request: Request, + ) -> Result, Status> { + tracing::error!("stop_provider"); + + todo!("stop_provider") } } diff --git a/test/main.tf b/test/main.tf index ef06f87..a5b08b1 100644 --- a/test/main.tf +++ b/test/main.tf @@ -5,3 +5,7 @@ terraform { } } } + +provider "terustform" {} + +resource "terustform_hello" "test1" {} \ No newline at end of file