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
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 5;
// 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
// mechanism to avoid proper type handling in providers.
//
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
// ==== DO NOT USE THIS ====
// ==== THIS MUST BE LEFT UNSET IN ALL OTHER SDKS ====
// ==== DO NOT USE THIS ====
bool legacy_type_system = 4;
}
}

View file

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

View file

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

View file

@ -81,7 +81,7 @@ impl Type {
pub type Value = BaseValue<ValueKind>;
#[derive(Debug)]
#[derive(PartialEq, Debug)]
pub enum ValueKind {
String(String),
Number(f64),
@ -111,7 +111,7 @@ impl ValueKind {
pub type StringValue = BaseValue<String>;
pub type I64Value = BaseValue<i64>;
#[derive(Debug)]
#[derive(PartialEq, Eq, Debug)]
pub enum BaseValue<T> {
Unknown,
Null,
@ -276,16 +276,27 @@ impl Value {
pub fn msg_unpack(data: &[u8], typ: &Type) -> DResult<Self> {
tracing::debug!(?typ, ?data, "Unpacking message");
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> {
use rmp::decode as mp;
let start = rd.position();
if let Ok(()) = mp::read_nil(rd) {
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 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 } => {
assert!(optionals.is_empty());
let len = mp::read_map_len(rd)?;
dbg!(len);
if attrs.len() != (len as usize) {
return Err(Diagnostic::error_string(format!(
@ -358,10 +370,13 @@ impl Value {
let elems = (0..len)
.map(|_| -> DResult<_> {
let key = read_string(rd)?;
dbg!(&key);
let typ = attrs.get(&key).ok_or_else(|| {
Diagnostic::error_string(format!("unexpected attribute: '{key}'"))
})?;
dbg!(typ);
let value = Value::msg_unpack_inner(rd, typ)?;
dbg!(&value);
Ok((key, value))
})
.collect::<DResult<BTreeMap<_, _>>>()?;
@ -388,3 +403,46 @@ impl 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()))
),
])))
);
}
}