mz_testdrive/action/
glue.rs1use anyhow::{Context, anyhow, bail};
11use aws_sdk_glue::types::{Compatibility, DataFormat, RegistryId, SchemaId};
12
13use crate::action::{ControlFlow, State};
14use crate::parser::BuiltinCommand;
15
16pub async fn run_create_schema(
49 mut cmd: BuiltinCommand,
50 state: &mut State,
51) -> Result<ControlFlow, anyhow::Error> {
52 let name = cmd.args.string("name")?;
53 let version_id_var = cmd.args.opt_string("set-version-id-var");
54 let registry = cmd.args.opt_string("registry");
55 let schema_arg = cmd.args.opt_string("schema");
56 let data_format = match cmd
57 .args
58 .opt_string("data-format")
59 .unwrap_or_else(|| "avro".into())
60 .to_lowercase()
61 .as_str()
62 {
63 "avro" => DataFormat::Avro,
64 "json" => DataFormat::Json,
65 "protobuf" => DataFormat::Protobuf,
66 other => bail!("unknown data-format: {}", other),
67 };
68 let compatibility = parse_compatibility(
69 &cmd.args
70 .opt_string("compatibility")
71 .unwrap_or_else(|| "backward".into()),
72 )?;
73 cmd.args.done()?;
74
75 let definition = match schema_arg {
79 Some(schema) => schema,
80 None => cmd.input.join("\n"),
81 };
82 if definition.trim().is_empty() {
83 bail!("glue-create-schema requires a `schema=` argument or a schema definition body");
84 }
85
86 println!(
87 "Registering Glue schema {:?} (registry {:?})...",
88 name,
89 registry.as_deref().unwrap_or("<default>"),
90 );
91
92 let glue = aws_sdk_glue::Client::new(&state.aws_config);
93
94 let mut create = glue
95 .create_schema()
96 .schema_name(&name)
97 .data_format(data_format)
98 .compatibility(compatibility)
99 .schema_definition(&definition);
100 if let Some(registry) = ®istry {
101 create = create.registry_id(RegistryId::builder().registry_name(registry).build());
102 }
103
104 let version_id = match create.send().await {
105 Ok(resp) => resp.schema_version_id().map(|s| s.to_string()),
106 Err(err) => {
107 let svc = err.into_service_error();
110 if svc.is_already_exists_exception() {
111 let mut schema_id = SchemaId::builder().schema_name(&name);
112 if let Some(registry) = ®istry {
113 schema_id = schema_id.registry_name(registry);
114 }
115 let resp = glue
116 .register_schema_version()
117 .schema_id(schema_id.build())
118 .schema_definition(&definition)
119 .send()
120 .await
121 .context("registering new Glue schema version")?;
122 resp.schema_version_id().map(|s| s.to_string())
123 } else {
124 return Err(anyhow::Error::new(svc).context("creating Glue schema"));
125 }
126 }
127 };
128 if let Some(var) = version_id_var {
129 let version_id =
130 version_id.ok_or_else(|| anyhow!("Glue did not return a schema version id"))?;
131 state.cmd_vars.insert(var, version_id);
132 }
133 Ok(ControlFlow::Continue)
134}
135
136pub async fn run_verify_compatibility(
151 mut cmd: BuiltinCommand,
152 state: &State,
153) -> Result<ControlFlow, anyhow::Error> {
154 let name = cmd.args.string("name")?;
155 let registry = cmd.args.opt_string("registry");
156 let expected = parse_compatibility(&cmd.args.string("compatibility")?)?;
157 cmd.args.done()?;
158
159 let glue = aws_sdk_glue::Client::new(&state.aws_config);
160 let mut schema_id = SchemaId::builder().schema_name(&name);
161 if let Some(registry) = ®istry {
162 schema_id = schema_id.registry_name(registry);
163 }
164 let resp = glue
165 .get_schema()
166 .schema_id(schema_id.build())
167 .send()
168 .await
169 .context("fetching Glue schema")?;
170
171 let actual = resp
172 .compatibility()
173 .ok_or_else(|| anyhow!("Glue schema {name:?} has no compatibility set"))?;
174 if *actual != expected {
175 bail!("Glue schema {name:?} has compatibility {actual:?}, expected {expected:?}");
176 }
177 Ok(ControlFlow::Continue)
178}
179
180fn parse_compatibility(s: &str) -> Result<Compatibility, anyhow::Error> {
183 Ok(match s.to_lowercase().as_str() {
184 "backward" => Compatibility::Backward,
185 "backward_all" => Compatibility::BackwardAll,
186 "forward" => Compatibility::Forward,
187 "forward_all" => Compatibility::ForwardAll,
188 "full" => Compatibility::Full,
189 "full_all" => Compatibility::FullAll,
190 "none" => Compatibility::None,
191 "disabled" => Compatibility::Disabled,
192 other => bail!("unknown compatibility: {}", other),
193 })
194}