mirror of
https://github.com/Noratrieb/terustform.git
synced 2026-01-14 08:30:13 +01:00
restructure modules
This commit is contained in:
parent
b86292fadb
commit
7e479e7a28
10 changed files with 114 additions and 114 deletions
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::DataSource;
|
||||
use crate::datasource::DataSource;
|
||||
|
||||
pub trait Provider: Send + Sync {
|
||||
fn name(&self) -> String;
|
||||
|
|
@ -1,9 +1,7 @@
|
|||
use crate::{
|
||||
framework::{
|
||||
datasource::{self, Mode},
|
||||
AttrPathSegment, Diagnostics,
|
||||
},
|
||||
datasource::{self, Mode},
|
||||
values::Type,
|
||||
AttrPathSegment, Diagnostics,
|
||||
};
|
||||
|
||||
use super::grpc::tfplugin6;
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue