Decode unknown in msgpack

This commit is contained in:
nora 2024-05-19 23:56:10 +02:00
parent 6d4fd2178e
commit 55506d3748
4 changed files with 72 additions and 10 deletions

View file

@ -462,9 +462,9 @@ message PlanResourceChange {
// specific details of the legacy SDK type system, and are not a general // specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers. // mechanism to avoid proper type handling in providers.
// //
// ==== DO NOT USE THIS ==== // ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ==== // ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ==== // ==== DO NOT USE THIS ====
bool legacy_type_system = 5; bool legacy_type_system = 5;
// deferred is set if the provider is deferring the change. If set the caller // deferred is set if the provider is deferring the change. If set the caller
@ -495,9 +495,9 @@ message ApplyResourceChange {
// specific details of the legacy SDK type system, and are not a general // specific details of the legacy SDK type system, and are not a general
// mechanism to avoid proper type handling in providers. // mechanism to avoid proper type handling in providers.
// //
// ==== DO NOT USE THIS ==== // ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ==== // ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ==== // ==== DO NOT USE THIS ====
bool legacy_type_system = 4; bool legacy_type_system = 4;
} }
} }

View file

@ -1,5 +1,6 @@
#![allow(unused_variables, unused_imports)] #![allow(unused_variables, unused_imports)]
pub mod tfplugin6 { pub mod tfplugin6 {
tonic::include_proto!("tfplugin6"); tonic::include_proto!("tfplugin6");
} }
@ -232,6 +233,7 @@ impl<P: crate::provider::Provider> Provider for super::ProviderHandler<P> {
&req.config, &req.config,
) )
.await; .await;
tracing::debug!(?new_state, ?diagnostics, "post apply_resource_change");
let reply = tfplugin6::apply_resource_change::Response { let reply = tfplugin6::apply_resource_change::Response {
new_state, new_state,

View file

@ -343,6 +343,8 @@ impl<P: Provider> ProviderHandler<P> {
tf_try!(rs.rs.update(config, planned_state, prior_state).await) tf_try!(rs.rs.update(config, planned_state, prior_state).await)
}; };
info!(?new_state, "Hello world");
(new_state.into_tfplugin(), TF_OK) (new_state.into_tfplugin(), TF_OK)
} }
} }

View file

@ -81,7 +81,7 @@ impl Type {
pub type Value = BaseValue<ValueKind>; pub type Value = BaseValue<ValueKind>;
#[derive(Debug)] #[derive(PartialEq, Debug)]
pub enum ValueKind { pub enum ValueKind {
String(String), String(String),
Number(f64), Number(f64),
@ -111,7 +111,7 @@ impl ValueKind {
pub type StringValue = BaseValue<String>; pub type StringValue = BaseValue<String>;
pub type I64Value = BaseValue<i64>; pub type I64Value = BaseValue<i64>;
#[derive(Debug)] #[derive(PartialEq, Eq, Debug)]
pub enum BaseValue<T> { pub enum BaseValue<T> {
Unknown, Unknown,
Null, Null,
@ -276,16 +276,27 @@ impl Value {
pub fn msg_unpack(data: &[u8], typ: &Type) -> DResult<Self> { pub fn msg_unpack(data: &[u8], typ: &Type) -> DResult<Self> {
tracing::debug!(?typ, ?data, "Unpacking message"); tracing::debug!(?typ, ?data, "Unpacking message");
let mut read = io::Cursor::new(data); let mut read = io::Cursor::new(data);
Self::msg_unpack_inner(&mut read, typ) Self::msg_unpack_inner(&mut read, typ).map_err(|mut diag| {
diag.diags[0].msg = format!("msgpack decoding error: {}", diag.diags[0].msg);
diag
})
} }
fn msg_unpack_inner(rd: &mut io::Cursor<&[u8]>, typ: &Type) -> DResult<Self> { fn msg_unpack_inner(rd: &mut io::Cursor<&[u8]>, typ: &Type) -> DResult<Self> {
use rmp::decode as mp; use rmp::decode as mp;
let start = rd.position();
if let Ok(()) = mp::read_nil(rd) { if let Ok(()) = mp::read_nil(rd) {
return Ok(Value::Null); return Ok(Value::Null);
} }
rd.set_position(rd.position() - 1); // revert past the nil rd.set_position(start);
// TODO: Handle unknown values better
// https://github.com/hashicorp/terraform/blob/main/docs/plugin-protocol/object-wire-format.md#schemaattribute-mapping-rules-for-messagepack
if let Ok(_) = mp::read_fixext1(rd) {
return Ok(Value::Unknown);
}
rd.set_position(start);
let read_string = |rd: &mut io::Cursor<&[u8]>| -> DResult<String> { 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 len = std::cmp::min(mp::read_str_len(rd)?, 1024 * 1024); // you're not gonna get more than a 1MB string...
@ -347,6 +358,7 @@ impl Value {
Type::Object { attrs, optionals } => { Type::Object { attrs, optionals } => {
assert!(optionals.is_empty()); assert!(optionals.is_empty());
let len = mp::read_map_len(rd)?; let len = mp::read_map_len(rd)?;
dbg!(len);
if attrs.len() != (len as usize) { if attrs.len() != (len as usize) {
return Err(Diagnostic::error_string(format!( return Err(Diagnostic::error_string(format!(
@ -358,10 +370,13 @@ impl Value {
let elems = (0..len) let elems = (0..len)
.map(|_| -> DResult<_> { .map(|_| -> DResult<_> {
let key = read_string(rd)?; let key = read_string(rd)?;
dbg!(&key);
let typ = attrs.get(&key).ok_or_else(|| { let typ = attrs.get(&key).ok_or_else(|| {
Diagnostic::error_string(format!("unexpected attribute: '{key}'")) Diagnostic::error_string(format!("unexpected attribute: '{key}'"))
})?; })?;
dbg!(typ);
let value = Value::msg_unpack_inner(rd, typ)?; let value = Value::msg_unpack_inner(rd, typ)?;
dbg!(&value);
Ok((key, value)) Ok((key, value))
}) })
.collect::<DResult<BTreeMap<_, _>>>()?; .collect::<DResult<BTreeMap<_, _>>>()?;
@ -388,3 +403,46 @@ impl Value {
Ok(Value::Known(value)) Ok(Value::Known(value))
} }
} }
#[cfg(test)]
mod test {
use std::collections::{BTreeMap, HashMap};
use crate::{Type, Value, ValueKind};
#[test]
fn decode_object() {
let typ = Type::Object {
attrs: HashMap::from([
("id".into(), Type::String),
("discord_id".into(), Type::String),
("name".into(), Type::String),
("description".into(), Type::String),
]),
optionals: vec![],
};
let data = [
132, 171, 100, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 163, 63, 63, 63, 170,
100, 105, 115, 99, 111, 114, 100, 95, 105, 100, 192, 162, 105, 100, 212, 0, 0, 164,
110, 97, 109, 101, 164, 109, 101, 111, 119,
];
let value = Value::msg_unpack(&data, &typ);
assert_eq!(
value.unwrap(),
Value::Known(ValueKind::Object(BTreeMap::from([
(
"description".into(),
Value::Known(ValueKind::String("???".into()))
),
("discord_id".into(), Value::Null),
("id".into(), Value::Unknown),
(
"name".into(),
Value::Known(ValueKind::String("meow".into()))
),
])))
);
}
}