mirror of
https://github.com/Noratrieb/terustform.git
synced 2026-01-14 16:35:11 +01:00
start parsing values incorrectly
This commit is contained in:
parent
c4e62f9d2d
commit
a7822229f3
8 changed files with 337 additions and 35 deletions
19
Cargo.lock
generated
19
Cargo.lock
generated
|
|
@ -950,6 +950,12 @@ version = "1.0.15"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
|
@ -976,6 +982,17 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.115"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
|
|
@ -1070,6 +1087,8 @@ dependencies = [
|
|||
"rcgen",
|
||||
"rmp",
|
||||
"rustls 0.23.4",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tempfile",
|
||||
"time",
|
||||
"tokio",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ 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"] }
|
||||
serde = "1.0.197"
|
||||
serde_json = "1.0.115"
|
||||
tempfile = "3.10.1"
|
||||
time = "0.3.35"
|
||||
tokio = { version = "1.37.0", features = ["full"] }
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
provider::Provider,
|
||||
DResult,
|
||||
},
|
||||
values::Value,
|
||||
values::{Value, ValueKind},
|
||||
};
|
||||
|
||||
pub struct ExampleProvider {}
|
||||
|
|
@ -61,16 +61,22 @@ impl DataSource for ExampleDataSource {
|
|||
}
|
||||
|
||||
fn read(&self, config: Value) -> DResult<Value> {
|
||||
Ok(Value::Object(BTreeMap::from([
|
||||
Ok(Value::Known(ValueKind::Object(BTreeMap::from([
|
||||
(
|
||||
"name".to_owned(),
|
||||
match config {
|
||||
Value::Object(mut obj) => obj.remove("name").unwrap(),
|
||||
Value::Known(ValueKind::Object(mut obj)) => obj.remove("name").unwrap(),
|
||||
_ => unreachable!(),
|
||||
},
|
||||
),
|
||||
("meow".to_owned(), Value::String("mrrrrr".to_owned())),
|
||||
("id".to_owned(), Value::String("0".to_owned())),
|
||||
])))
|
||||
(
|
||||
"meow".to_owned(),
|
||||
Value::Known(ValueKind::String("mrrrrr".to_owned())),
|
||||
),
|
||||
(
|
||||
"id".to_owned(),
|
||||
Value::Known(ValueKind::String("0".to_owned())),
|
||||
),
|
||||
]))))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::values::Value;
|
||||
use crate::values::{Type, Value};
|
||||
|
||||
use super::DResult;
|
||||
|
||||
|
|
@ -56,4 +56,26 @@ impl Mode {
|
|||
pub fn computed(&self) -> bool {
|
||||
matches!(self, Self::OptionalComputed | Self::Computed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Schema {
|
||||
pub fn typ(&self) -> Type {
|
||||
let attrs = self
|
||||
.attributes
|
||||
.iter()
|
||||
.map(|(name, attr)| {
|
||||
let attr_type = match attr {
|
||||
Attribute::Int64 { .. } => Type::Number,
|
||||
Attribute::String { .. } => Type::String,
|
||||
};
|
||||
|
||||
(name.clone(), attr_type)
|
||||
})
|
||||
.collect();
|
||||
|
||||
Type::Object {
|
||||
attrs,
|
||||
optionals: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,3 +10,17 @@ pub struct Diagnostics {
|
|||
}
|
||||
|
||||
pub type DResult<T> = Result<T, Diagnostics>;
|
||||
|
||||
impl Diagnostics {
|
||||
pub fn error_string(msg: String) -> Self {
|
||||
Self {
|
||||
errors: vec![msg],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: std::error::Error + std::fmt::Debug> From<E> for Diagnostics {
|
||||
fn from(value: E) -> Self {
|
||||
Self::error_string(format!("{:?}", value))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -237,10 +237,32 @@ impl Provider for super::ProviderHandler {
|
|||
.get(&request.get_ref().type_name)
|
||||
.unwrap();
|
||||
|
||||
let state = ds.read(crate::values::Value::Object(BTreeMap::from([(
|
||||
"name".to_owned(),
|
||||
crate::values::Value::String("mykitten".to_owned()),
|
||||
)])));
|
||||
let typ = ds.schema().typ();
|
||||
let config = match &request.get_ref().config {
|
||||
None => crate::values::Value::Null,
|
||||
Some(v) => {
|
||||
let value = crate::values::Value::msg_unpack(&v.msgpack, &typ);
|
||||
match value {
|
||||
Ok(value) => value,
|
||||
Err(errs) => {
|
||||
return Ok(Response::new(tfplugin6::read_data_source::Response {
|
||||
deferred: None,
|
||||
state: None,
|
||||
diagnostics: errs.to_tfplugin_diags(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let state = ds.read(crate::values::Value::Known(
|
||||
crate::values::ValueKind::Object(BTreeMap::from([(
|
||||
"name".to_owned(),
|
||||
crate::values::Value::Known(crate::values::ValueKind::String(
|
||||
"mykitten".to_owned(),
|
||||
)),
|
||||
)])),
|
||||
));
|
||||
let (state, diagnostics) = match state {
|
||||
Ok(s) => (
|
||||
Some(tfplugin6::DynamicValue {
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ use std::collections::HashMap;
|
|||
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use crate::framework::datasource::{self, DataSource};
|
||||
use crate::framework::datasource::DataSource;
|
||||
use crate::framework::provider::Provider;
|
||||
use crate::framework::DResult;
|
||||
|
||||
pub use grpc::plugin::grpc_controller_server::GrpcControllerServer;
|
||||
pub use grpc::tfplugin6::provider_server::ProviderServer;
|
||||
|
|
|
|||
260
src/values.rs
260
src/values.rs
|
|
@ -1,32 +1,102 @@
|
|||
// check terraform-plugin-go tfprotov6/internal/toproto for convesions
|
||||
// tftypes for types and values
|
||||
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::{
|
||||
collections::{BTreeMap, HashMap, HashSet},
|
||||
io::{self, Read},
|
||||
};
|
||||
|
||||
use rmp::encode::write_bool;
|
||||
|
||||
use crate::framework::{DResult, Diagnostics};
|
||||
|
||||
pub enum Type {
|
||||
Bool,
|
||||
Number,
|
||||
String,
|
||||
Dynamic,
|
||||
/// A list of elements of the same type.
|
||||
List {
|
||||
elem: Box<Type>,
|
||||
},
|
||||
/// A bunch of unordered string-value pair of the same type.
|
||||
Map {
|
||||
elem: Box<Type>,
|
||||
},
|
||||
/// A set of unique values of the same type.
|
||||
Set {
|
||||
elem: Box<Type>,
|
||||
},
|
||||
/// A bunch of unordered string-value pairs of different types.
|
||||
/// The attributes are statically known.
|
||||
Object {
|
||||
attrs: HashMap<String, Type>,
|
||||
/// The attributes in `attrs` that are optional.
|
||||
/// Always empty for now because of JSON reasons.
|
||||
optionals: Vec<String>,
|
||||
},
|
||||
/// An ordered list of values of different types.
|
||||
Tuple {
|
||||
elems: Vec<Type>,
|
||||
},
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn to_json(&self) -> String {
|
||||
match *self {
|
||||
Self::String => "\"string\"".to_owned(),
|
||||
Self::Number => "\"number\"".to_owned(),
|
||||
let value = self.to_json_inner();
|
||||
serde_json::to_string(&value).unwrap()
|
||||
}
|
||||
pub fn to_json_inner(&self) -> serde_json::Value {
|
||||
use serde_json::Value;
|
||||
|
||||
let compound =
|
||||
|tag: &str, inner: Value| Value::Array(vec![Value::String(tag.to_owned()), inner]);
|
||||
|
||||
match self {
|
||||
Self::Bool => Value::String("bool".to_owned()),
|
||||
Self::String => Value::String("string".to_owned()),
|
||||
Self::Number => Value::String("number".to_owned()),
|
||||
Self::Dynamic => Value::String("dynamic".to_owned()),
|
||||
Self::List { elem } => compound("list", elem.to_json_inner()),
|
||||
Self::Map { elem } => compound("map", elem.to_json_inner()),
|
||||
Self::Set { elem } => compound("set", elem.to_json_inner()),
|
||||
Self::Object {
|
||||
attrs,
|
||||
optionals: _,
|
||||
} => compound(
|
||||
"object",
|
||||
Value::Object(
|
||||
attrs
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_json_inner()))
|
||||
.collect(),
|
||||
),
|
||||
),
|
||||
Self::Tuple { elems } => compound(
|
||||
"tuple",
|
||||
elems.iter().map(|elem| elem.to_json_inner()).collect(),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is very dumb and wrong
|
||||
#[derive(Debug)]
|
||||
pub enum Value {
|
||||
String(String),
|
||||
Object(BTreeMap<String, Value>),
|
||||
Known(ValueKind),
|
||||
Unknown,
|
||||
Null,
|
||||
}
|
||||
|
||||
impl Value {
|
||||
pub fn ty(&self) -> Type {
|
||||
todo!()
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum ValueKind {
|
||||
String(String),
|
||||
Number(f64),
|
||||
Bool(bool),
|
||||
List(Vec<Value>),
|
||||
Set(Vec<Value>),
|
||||
Map(BTreeMap<String, Value>),
|
||||
Tuple(Vec<Value>),
|
||||
Object(BTreeMap<String, Value>),
|
||||
}
|
||||
|
||||
// marshal msg pack
|
||||
|
|
@ -35,22 +105,170 @@ impl Value {
|
|||
impl Value {
|
||||
pub fn msg_pack(&self) -> Vec<u8> {
|
||||
let mut buf = Vec::new();
|
||||
self.msg_pack_inner(&mut buf);
|
||||
self.msg_pack_inner(&mut buf)
|
||||
.expect("writing to Vec<u8> cannot fail");
|
||||
buf
|
||||
}
|
||||
|
||||
pub fn msg_pack_inner(&self, v: &mut Vec<u8>) {
|
||||
match self {
|
||||
Value::String(s) => {
|
||||
rmp::encode::write_str(v, s).unwrap();
|
||||
pub fn msg_pack_inner(&self, wr: &mut Vec<u8>) -> std::io::Result<()> {
|
||||
use rmp::encode as mp;
|
||||
|
||||
let known = match self {
|
||||
Value::Unknown => {
|
||||
wr.extend_from_slice(&[0xd4, 0, 0]);
|
||||
return Ok(());
|
||||
}
|
||||
Value::Object(o) => {
|
||||
rmp::encode::write_map_len(v, o.len().try_into().unwrap()).unwrap();
|
||||
Value::Null => {
|
||||
mp::write_nil(wr)?;
|
||||
return Ok(());
|
||||
}
|
||||
Value::Known(known) => known,
|
||||
};
|
||||
|
||||
match known {
|
||||
ValueKind::String(s) => {
|
||||
mp::write_str(wr, s)?;
|
||||
}
|
||||
&ValueKind::Number(n) => {
|
||||
if n.is_infinite() {
|
||||
if n.signum() == -1.0 {
|
||||
mp::write_f64(wr, f64::NEG_INFINITY)?;
|
||||
} else {
|
||||
mp::write_f64(wr, f64::INFINITY)?;
|
||||
}
|
||||
} else if (n as i64 as f64) == n {
|
||||
// is int
|
||||
mp::write_i64(wr, n as i64)?;
|
||||
} else {
|
||||
mp::write_f64(wr, n)?;
|
||||
}
|
||||
// Terraform handles bigfloats but we do emphatically not care
|
||||
}
|
||||
ValueKind::Bool(b) => {
|
||||
mp::write_bool(wr, *b)?;
|
||||
}
|
||||
ValueKind::List(elems) | ValueKind::Set(elems) | ValueKind::Tuple(elems) => {
|
||||
mp::write_array_len(wr, elems.len().try_into().unwrap())?;
|
||||
for elem in elems {
|
||||
elem.msg_pack_inner(wr)?;
|
||||
}
|
||||
}
|
||||
ValueKind::Map(o) | ValueKind::Object(o) => {
|
||||
mp::write_map_len(wr, o.len().try_into().unwrap())?;
|
||||
for (key, val) in o {
|
||||
rmp::encode::write_str(v, key).unwrap();
|
||||
val.msg_pack_inner(v);
|
||||
mp::write_str(wr, key)?;
|
||||
val.msg_pack_inner(wr)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn msg_unpack(data: &[u8], typ: &Type) -> DResult<Self> {
|
||||
let mut read = io::Cursor::new(data);
|
||||
Self::msg_unpack_inner(&mut read, typ)
|
||||
}
|
||||
|
||||
fn msg_unpack_inner(rd: &mut io::Cursor<&[u8]>, typ: &Type) -> DResult<Self> {
|
||||
use rmp::decode as mp;
|
||||
|
||||
if let Ok(()) = mp::read_nil(rd) {
|
||||
return Ok(Value::Null);
|
||||
}
|
||||
rd.set_position(rd.position() - 1); // revert past the nil
|
||||
|
||||
let read_string = |rd: &mut io::Cursor<&[u8]>| -> DResult<String> {
|
||||
let len = std::cmp::min(mp::read_str_len(rd)?, 1024 * 1024); // you're not gonna get more than a 1MB string...
|
||||
let mut buf = Vec::with_capacity(len as usize);
|
||||
rd.read_exact(&mut buf)?;
|
||||
Ok(String::from_utf8(buf)?)
|
||||
};
|
||||
|
||||
let value = match typ {
|
||||
Type::Bool => {
|
||||
let b = mp::read_bool(rd)?;
|
||||
ValueKind::Bool(b)
|
||||
}
|
||||
Type::Number => {
|
||||
let prev = rd.position();
|
||||
if let Ok(int) = mp::read_int::<i64, _>(rd) {
|
||||
ValueKind::Number(int as f64)
|
||||
} else {
|
||||
rd.set_position(prev);
|
||||
if let Ok(f32) = mp::read_f32(rd) {
|
||||
ValueKind::Number(f32 as f64)
|
||||
} else {
|
||||
rd.set_position(prev);
|
||||
let f64 = mp::read_f64(rd)?;
|
||||
ValueKind::Number(f64)
|
||||
}
|
||||
}
|
||||
}
|
||||
Type::String => ValueKind::String(read_string(rd)?),
|
||||
Type::Dynamic => todo!("dynamic"),
|
||||
Type::List { elem } => {
|
||||
let len = mp::read_array_len(rd)?;
|
||||
let elems = (0..len)
|
||||
.map(|_| Value::msg_unpack_inner(rd, &elem))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ValueKind::List(elems)
|
||||
}
|
||||
Type::Map { elem } => {
|
||||
let len = mp::read_array_len(rd)?;
|
||||
let elems = (0..len)
|
||||
.map(|_| -> DResult<_> {
|
||||
let key = read_string(rd)?;
|
||||
let value = Value::msg_unpack_inner(rd, &elem)?;
|
||||
Ok((key, value))
|
||||
})
|
||||
.collect::<DResult<BTreeMap<_, _>>>()?;
|
||||
ValueKind::Map(elems)
|
||||
}
|
||||
Type::Set { elem } => {
|
||||
let len = mp::read_array_len(rd)?;
|
||||
let elems = (0..len)
|
||||
.map(|_| Value::msg_unpack_inner(rd, &elem))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ValueKind::Set(elems)
|
||||
}
|
||||
Type::Object { attrs, optionals } => {
|
||||
assert!(optionals.is_empty());
|
||||
let len = mp::read_array_len(rd)?;
|
||||
if attrs.len() != (len as usize) {
|
||||
return Err(Diagnostics::error_string(format!(
|
||||
"expected {} attrs, found {len} attrs in object",
|
||||
attrs.len()
|
||||
)));
|
||||
}
|
||||
let elems = (0..len)
|
||||
.map(|_| -> DResult<_> {
|
||||
let key = read_string(rd)?;
|
||||
let typ = attrs.get(&key).ok_or_else(|| {
|
||||
Diagnostics::error_string(format!("unexpected attribute: {key}"))
|
||||
})?;
|
||||
let value = Value::msg_unpack_inner(rd, &typ)?;
|
||||
Ok((key, value))
|
||||
})
|
||||
.collect::<DResult<BTreeMap<_, _>>>()?;
|
||||
ValueKind::Object(elems)
|
||||
}
|
||||
Type::Tuple { elems } => {
|
||||
let len = mp::read_array_len(rd)?;
|
||||
if elems.len() != (len as usize) {
|
||||
return Err(Diagnostics::error_string(format!(
|
||||
"expected {} elems, found {len} elems in tuple",
|
||||
elems.len()
|
||||
)));
|
||||
}
|
||||
let elems = elems
|
||||
.iter()
|
||||
.map(|typ| Value::msg_unpack_inner(rd, &typ))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
ValueKind::List(elems)
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Value::Known(value))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue