restructure modules

This commit is contained in:
nora 2024-04-15 20:22:45 +02:00
parent b86292fadb
commit 7e479e7a28
10 changed files with 114 additions and 114 deletions

View file

@ -1,17 +1,15 @@
use std::collections::HashMap;
use terustform::{
framework::{
datasource::{self, DataSource},
provider::Provider,
AttrPath, DResult, StringValue, ValueModel,
},
datasource::{self, DataSource},
provider::Provider,
values::Value,
AttrPath, DResult, StringValue, ValueModel,
};
#[tokio::main]
async fn main() -> eyre::Result<()> {
terustform::serve(&ExampleProvider {}).await
terustform::start(&ExampleProvider {}).await
}
pub struct ExampleProvider {}
@ -28,7 +26,7 @@ impl Provider for ExampleProvider {
struct ExampleDataSource {}
#[derive(terustform::DataSourceModel)]
#[derive(terustform::Model)]
struct ExampleDataSourceModel {
name: StringValue,
meow: StringValue,

View file

@ -3,7 +3,7 @@ use syn::spanned::Spanned;
// This macro should only reference items in `terustform::__derive_private`.
#[proc_macro_derive(DataSourceModel)]
#[proc_macro_derive(Model)]
pub fn data_source_model(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
match data_source_model_inner(input) {

View file

@ -1,12 +1,5 @@
#![allow(dead_code)]
pub mod datasource;
pub mod provider;
use crate::values::{Value, ValueKind};
use self::datasource::DataSource;
#[derive(Debug, Default)]
pub struct Diagnostics {
pub(crate) diags: Vec<Diagnostic>,

View file

@ -1,113 +1,33 @@
mod cert;
pub mod framework;
mod base;
pub mod datasource;
pub mod provider;
mod server;
pub mod values;
pub use terustform_macros::DataSourceModel;
pub use base::*;
pub use terustform_macros::Model;
use std::{env, path::PathBuf};
use provider::Provider;
use base64::Engine;
use eyre::{bail, Context, Result};
use framework::provider::Provider;
use tokio::net::UnixListener;
use tonic::transport::{Certificate, ServerTlsConfig};
use tracing::{info, Level};
use tracing::Level;
pub async fn serve(provider: &dyn Provider) -> eyre::Result<()> {
pub async fn start(provider: &dyn Provider) -> eyre::Result<()> {
tracing_subscriber::fmt()
.with_max_level(Level::DEBUG)
.with_writer(std::io::stderr)
.without_time()
.init();
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);
bail!("init error");
}
};
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);
let shutdown = tokio_util::sync::CancellationToken::new();
let server = tonic::transport::Server::builder()
.tls_config(tls)
.wrap_err("invalid TLS config")?
.add_service(server::ProviderServer::new(server::ProviderHandler::new(
shutdown.clone(),
provider,
)))
.add_service(server::GrpcControllerServer::new(server::Controller {
shutdown: shutdown.clone(),
}))
.serve_with_incoming(uds_stream);
tokio::select! {
_ = shutdown.cancelled() => {}
result = server => {
result.wrap_err("failed to start server")?;
}
}
Ok(())
}
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 _ = env::var("PLUGIN_MIN_PORT")
.wrap_err("PLUGIN_MIN_PORT not found")?
.parse::<u16>()
.wrap_err("PLUGIN_MIN_PORT not an int")?;
let _ = env::var("PLUGIN_MAX_PORT")
.wrap_err("PLUGIN_MAX_PORT not found")?
.parse::<u16>()
.wrap_err("PLUGIN_MAX_PORT not an int")?;
let tmpdir = tempfile::TempDir::new().wrap_err("failed to create temporary directory")?;
let socket = tmpdir.path().join("plugin");
// 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());
println!("{CORE_PROTOCOL_VERSION}|{PROTO_VERSION}|{listener_addr_network}|{listener_addr}|{proto_type}|{b64_cert}");
Ok((tmpdir, socket))
server::serve(provider).await
}
/// Private, only for use for with the derive macro.
#[doc(hidden)]
pub mod __derive_private {
pub use crate::framework::{
pub use crate::values::{Value, ValueKind};
pub use crate::{
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, ValueModel,
};
pub use crate::values::{Value, ValueKind};
pub use {Clone, Option::Some, Result::Err, ToOwned};
pub fn new_object<const N: usize>(elems: [(&str, Value); N]) -> Value {

View file

@ -1,4 +1,4 @@
use super::DataSource;
use crate::datasource::DataSource;
pub trait Provider: Send + Sync {
fn name(&self) -> String;

View file

@ -1,9 +1,7 @@
use crate::{
framework::{
datasource::{self, Mode},
AttrPathSegment, Diagnostics,
},
datasource::{self, Mode},
values::Type,
AttrPathSegment, Diagnostics,
};
use super::grpc::tfplugin6;

View file

@ -1,12 +1,20 @@
mod cert;
mod convert;
mod grpc;
use std::collections::HashMap;
use std::env;
use std::path::PathBuf;
use base64::Engine;
use eyre::{bail, Context};
use tokio::net::UnixListener;
use tokio_util::sync::CancellationToken;
use tonic::transport::{Certificate, ServerTlsConfig};
use tracing::info;
use crate::framework::datasource::DataSource;
use crate::framework::provider::Provider;
use crate::datasource::DataSource;
use crate::provider::Provider;
pub use grpc::plugin::grpc_controller_server::GrpcControllerServer;
pub use grpc::tfplugin6::provider_server::ProviderServer;
@ -86,3 +94,86 @@ struct Schemas {
data_sources: HashMap<String, tfplugin6::Schema>,
diagnostics: Vec<tfplugin6::Diagnostic>,
}
pub async fn serve(provider: &dyn Provider) -> eyre::Result<()> {
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);
bail!("init error");
}
};
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);
let shutdown = tokio_util::sync::CancellationToken::new();
let server = tonic::transport::Server::builder()
.tls_config(tls)
.wrap_err("invalid TLS config")?
.add_service(ProviderServer::new(ProviderHandler::new(
shutdown.clone(),
provider,
)))
.add_service(GrpcControllerServer::new(Controller {
shutdown: shutdown.clone(),
}))
.serve_with_incoming(uds_stream);
tokio::select! {
_ = shutdown.cancelled() => {}
result = server => {
result.wrap_err("failed to start server")?;
}
}
Ok(())
}
const _MAGIC_COOKIE_KEY: &str = "TF_PLUGIN_MAGIC_COOKIE";
const _MAGIC_COOKIE_VALUE: &str =
"d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2";
async fn init_handshake(
server_cert: &rcgen::Certificate,
) -> eyre::Result<(tempfile::TempDir, PathBuf)> {
// https://github.com/hashicorp/go-plugin/blob/8d2aaa458971cba97c3bfec1b0380322e024b514/docs/internals.md
let _ = env::var("PLUGIN_MIN_PORT")
.wrap_err("PLUGIN_MIN_PORT not found")?
.parse::<u16>()
.wrap_err("PLUGIN_MIN_PORT not an int")?;
let _ = env::var("PLUGIN_MAX_PORT")
.wrap_err("PLUGIN_MAX_PORT not found")?
.parse::<u16>()
.wrap_err("PLUGIN_MAX_PORT not an int")?;
let tmpdir = tempfile::TempDir::new().wrap_err("failed to create temporary directory")?;
let socket = tmpdir.path().join("plugin");
// 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());
println!("{CORE_PROTOCOL_VERSION}|{PROTO_VERSION}|{listener_addr_network}|{listener_addr}|{proto_type}|{b64_cert}");
Ok((tmpdir, socket))
}

View file

@ -6,7 +6,7 @@ use std::{
io::{self, Read},
};
use crate::framework::{BaseValue, DResult, Diagnostic};
use crate::{BaseValue, DResult, Diagnostic};
#[derive(Debug)]
pub enum Type {