pub trait Provider: Send + Sync {
// Required methods
fn get_schema<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<ProviderSchema, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn configure<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
config: &'life1 DynamicValue,
terraform_version: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn plan_resource_change<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
prior_state: &'life2 DynamicValue,
proposed_new_state: &'life3 DynamicValue,
config: &'life4 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<PlannedChange, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait;
fn apply_resource_change<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
prior_state: &'life2 DynamicValue,
planned_state: &'life3 DynamicValue,
config: &'life4 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<DynamicValue, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait;
fn read_resource<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
current_state: &'life2 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn read_data_source<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
config: &'life2 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn import_resource_state<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn upgrade_resource_state<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
stored_version: i64,
raw_json: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<DynamicValue, ProviderError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
}Expand description
A provider: the 8 operations magma performs against one, over
magma_cty values.
── THE WHOLE CONTRACT, AND IT IS SMALL ────────────────────────────── This is every call the apply engine makes. There is no ninth. That matters, because the surface being this small is what makes a native provider tractable at all — the cost of a provider is its API bindings, never its protocol.
── Send + Sync, AND Sync IS NOT DECORATION ─────────────────────
A LiveProvider is held across .await points inside futures that
pangea-operator requires to be Sync, so a Box<dyn Provider> that
is merely Send fails to compile at the CONSUMER — six E0277s in
another repo, pointing at the operator’s own functions rather than at
this line. The concrete ProviderConn this replaced was Sync
incidentally, so the bound was being satisfied by accident and
erasing it to a trait object is what exposed the requirement.
── &mut self, NOT &self ─────────────────────────────────────────
Deliberate, and it constrains the shape downstream. The tonic clients
behind ProviderConn need &mut per call, so a &self trait would
force interior mutability on the ONE implementation that exists
today, to buy sharing that no caller wants: each LiveProvider owns
its connection exclusively. Callers therefore hold Box<dyn Provider>
(owned), while the FACTORY is what gets shared. A native provider
that happens to be stateless can simply ignore the &mut.
── ORDERING IS A REAL PRECONDITION ──────────────────────────────────
configure MUST run before any operation other than get_schema.
The tfplugin protocol requires it, and providers on both SDKv2 and
terraform-plugin-framework cache credentials there — some
nil-dereference when called unconfigured. The trait cannot express
this (it is a sequencing rule, not a type), so a native implementation
must state what it does when called out of order rather than assume
the engine’s ordering holds. dial_configured_provider is the one
place that establishes it.
Required Methods§
Sourcefn get_schema<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<ProviderSchema, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn get_schema<'life0, 'async_trait>(
&'life0 mut self,
) -> Pin<Box<dyn Future<Output = Result<ProviderSchema, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
The provider’s schema, reduced to implied cty types.
Sourcefn configure<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
config: &'life1 DynamicValue,
terraform_version: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn configure<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
config: &'life1 DynamicValue,
terraform_version: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Provider credentials / settings. See the ordering note above.
Sourcefn plan_resource_change<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
prior_state: &'life2 DynamicValue,
proposed_new_state: &'life3 DynamicValue,
config: &'life4 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<PlannedChange, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn plan_resource_change<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
prior_state: &'life2 DynamicValue,
proposed_new_state: &'life3 DynamicValue,
config: &'life4 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<PlannedChange, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
The provider’s proposed new state PLUS its requires_replace
verdict — the only authoritative source for replace-vs-update.
Sourcefn apply_resource_change<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
prior_state: &'life2 DynamicValue,
planned_state: &'life3 DynamicValue,
config: &'life4 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<DynamicValue, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn apply_resource_change<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
prior_state: &'life2 DynamicValue,
planned_state: &'life3 DynamicValue,
config: &'life4 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<DynamicValue, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Execute the change; returns the new state.
A partial apply — the resource is committed but a follow-up call
failed — is ProviderError::PartiallyApplied, carrying the state.
An implementation that loses that state orphans real resources;
see that variant’s doc for the measured EIP case.
Sourcefn read_resource<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
current_state: &'life2 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn read_resource<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
current_state: &'life2 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Refresh. Ok(None) means the resource no longer exists, so the
caller drops it from state — distinct from an error.
Sourcefn read_data_source<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
config: &'life2 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn read_data_source<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
config: &'life2 DynamicValue,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Read a data source, so ${data.<type>.<name>.<attr>} resolves.
Sourcefn import_resource_state<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn import_resource_state<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<Option<DynamicValue>, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Adopt an existing resource by id — the import half that powers
import-on-create-conflict and magma import.
Sourcefn upgrade_resource_state<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
stored_version: i64,
raw_json: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<DynamicValue, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn upgrade_resource_state<'life0, 'life1, 'life2, 'async_trait>(
&'life0 mut self,
type_name: &'life1 str,
stored_version: i64,
raw_json: &'life2 [u8],
) -> Pin<Box<dyn Future<Output = Result<DynamicValue, ProviderError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Migrate stored attribute JSON written under an older schema version up to the current one.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".