mirror of
https://github.com/Noratrieb/terustform.git
synced 2026-01-14 16:35:11 +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 std::collections::HashMap;
|
||||||
|
|
||||||
use terustform::{
|
use terustform::{
|
||||||
framework::{
|
datasource::{self, DataSource},
|
||||||
datasource::{self, DataSource},
|
provider::Provider,
|
||||||
provider::Provider,
|
|
||||||
AttrPath, DResult, StringValue, ValueModel,
|
|
||||||
},
|
|
||||||
values::Value,
|
values::Value,
|
||||||
|
AttrPath, DResult, StringValue, ValueModel,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> eyre::Result<()> {
|
async fn main() -> eyre::Result<()> {
|
||||||
terustform::serve(&ExampleProvider {}).await
|
terustform::start(&ExampleProvider {}).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ExampleProvider {}
|
pub struct ExampleProvider {}
|
||||||
|
|
@ -28,7 +26,7 @@ impl Provider for ExampleProvider {
|
||||||
|
|
||||||
struct ExampleDataSource {}
|
struct ExampleDataSource {}
|
||||||
|
|
||||||
#[derive(terustform::DataSourceModel)]
|
#[derive(terustform::Model)]
|
||||||
struct ExampleDataSourceModel {
|
struct ExampleDataSourceModel {
|
||||||
name: StringValue,
|
name: StringValue,
|
||||||
meow: StringValue,
|
meow: StringValue,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use syn::spanned::Spanned;
|
||||||
|
|
||||||
// This macro should only reference items in `terustform::__derive_private`.
|
// 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 {
|
pub fn data_source_model(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||||
let input = syn::parse_macro_input!(input as syn::DeriveInput);
|
let input = syn::parse_macro_input!(input as syn::DeriveInput);
|
||||||
match data_source_model_inner(input) {
|
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 crate::values::{Value, ValueKind};
|
||||||
|
|
||||||
use self::datasource::DataSource;
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Diagnostics {
|
pub struct Diagnostics {
|
||||||
pub(crate) diags: Vec<Diagnostic>,
|
pub(crate) diags: Vec<Diagnostic>,
|
||||||
|
|
@ -1,113 +1,33 @@
|
||||||
mod cert;
|
mod base;
|
||||||
pub mod framework;
|
pub mod datasource;
|
||||||
|
pub mod provider;
|
||||||
mod server;
|
mod server;
|
||||||
pub mod values;
|
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 tracing::Level;
|
||||||
use eyre::{bail, Context, Result};
|
|
||||||
use framework::provider::Provider;
|
|
||||||
use tokio::net::UnixListener;
|
|
||||||
use tonic::transport::{Certificate, ServerTlsConfig};
|
|
||||||
use tracing::{info, Level};
|
|
||||||
|
|
||||||
pub async fn serve(provider: &dyn Provider) -> eyre::Result<()> {
|
pub async fn start(provider: &dyn Provider) -> eyre::Result<()> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_max_level(Level::DEBUG)
|
.with_max_level(Level::DEBUG)
|
||||||
.with_writer(std::io::stderr)
|
.with_writer(std::io::stderr)
|
||||||
.without_time()
|
.without_time()
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let client_cert =
|
server::serve(provider).await
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Private, only for use for with the derive macro.
|
/// Private, only for use for with the derive macro.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod __derive_private {
|
pub mod __derive_private {
|
||||||
pub use crate::framework::{
|
pub use crate::values::{Value, ValueKind};
|
||||||
|
pub use crate::{
|
||||||
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, ValueModel,
|
AttrPath, AttrPathSegment, BaseValue, DResult, Diagnostic, Diagnostics, ValueModel,
|
||||||
};
|
};
|
||||||
pub use crate::values::{Value, ValueKind};
|
|
||||||
pub use {Clone, Option::Some, Result::Err, ToOwned};
|
pub use {Clone, Option::Some, Result::Err, ToOwned};
|
||||||
|
|
||||||
pub fn new_object<const N: usize>(elems: [(&str, Value); N]) -> Value {
|
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 {
|
pub trait Provider: Send + Sync {
|
||||||
fn name(&self) -> String;
|
fn name(&self) -> String;
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
framework::{
|
datasource::{self, Mode},
|
||||||
datasource::{self, Mode},
|
|
||||||
AttrPathSegment, Diagnostics,
|
|
||||||
},
|
|
||||||
values::Type,
|
values::Type,
|
||||||
|
AttrPathSegment, Diagnostics,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::grpc::tfplugin6;
|
use super::grpc::tfplugin6;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
|
mod cert;
|
||||||
mod convert;
|
mod convert;
|
||||||
mod grpc;
|
mod grpc;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
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 tokio_util::sync::CancellationToken;
|
||||||
|
use tonic::transport::{Certificate, ServerTlsConfig};
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
use crate::framework::datasource::DataSource;
|
use crate::datasource::DataSource;
|
||||||
use crate::framework::provider::Provider;
|
use crate::provider::Provider;
|
||||||
|
|
||||||
pub use grpc::plugin::grpc_controller_server::GrpcControllerServer;
|
pub use grpc::plugin::grpc_controller_server::GrpcControllerServer;
|
||||||
pub use grpc::tfplugin6::provider_server::ProviderServer;
|
pub use grpc::tfplugin6::provider_server::ProviderServer;
|
||||||
|
|
@ -86,3 +94,86 @@ struct Schemas {
|
||||||
data_sources: HashMap<String, tfplugin6::Schema>,
|
data_sources: HashMap<String, tfplugin6::Schema>,
|
||||||
diagnostics: Vec<tfplugin6::Diagnostic>,
|
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},
|
io::{self, Read},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::framework::{BaseValue, DResult, Diagnostic};
|
use crate::{BaseValue, DResult, Diagnostic};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue