pub struct S3 { /* private fields */ }Expand description
An object in S3, as a configuration source.
Implementations§
Source§impl S3
impl S3
Sourcepub async fn new(
bucket: impl Into<String>,
key: impl Into<Keys>,
) -> Result<Self, Error>
pub async fn new( bucket: impl Into<String>, key: impl Into<Keys>, ) -> Result<Self, Error>
The object key in bucket, with credentials from the environment.
key is a key — "prod/db.json" — or a Keys, for the
several-objects and prefix forms.
The format is taken from the key’s extension — prod/db.json is JSON. A
key without one, and every prefix, needs
with_format.
This resolves credentials, which may read a file or call the instance metadata service — the one constructor in this family that does I/O, because the credential chain is what it is.
Sourcepub fn with_config(
config: &SdkConfig,
bucket: impl Into<String>,
key: impl Into<Keys>,
) -> Self
pub fn with_config( config: &SdkConfig, bucket: impl Into<String>, key: impl Into<Keys>, ) -> Self
Uses an SdkConfig the program already built.
For a caller that already talks to AWS, and for anything that is not AWS: MinIO, Ceph, R2 and B2 all speak this API, and all of them need an endpoint override the environment cannot express.
let config = aws_config::from_env()
.endpoint_url("http://minio.internal:9000")
.load()
.await;
let s3 = S3::with_config(&config, "myapp-config", "prod/db.json");Sourcepub fn with_tls(
config: &SdkConfig,
bucket: impl Into<String>,
key: impl Into<Keys>,
tls: &TlsConfig,
) -> Result<Self, Error>
pub fn with_tls( config: &SdkConfig, bucket: impl Into<String>, key: impl Into<Keys>, tls: &TlsConfig, ) -> Result<Self, Error>
As with_config, with a private certificate
authority.
The same vocabulary as the other six store crates, spelled as data —
nothing here names an SDK or a rustls type:
let config = aws_config::from_env()
.endpoint_url("https://minio.internal:9000")
.load()
.await;
let s3 = S3::with_tls(
&config,
"myapp-config",
"prod/db.json",
&TlsConfig::new().with_ca_certificate_file("/etc/ssl/private-ca.pem"),
)?;This is for the S3-compatible servers, which is where a private authority actually turns up: MinIO, Ceph and a company’s own gateway all present certificates AWS’ public chain has never heard of.
§What S3 cannot express
A client certificate. The SDK reaches TLS through
aws-smithy-http-client, whose TlsContext has a trust store and
nothing else — there is no client-certificate slot to fill, at any
version this crate can depend on. So
with_client_certificate_files and with_client_certificate_pem
are refused here, naming the call and pointing at
from_client — not ignored, because a caller who
asked to present a certificate and did not would discover it as an
authentication failure a long way from the cause.
A caller who needs mTLS to an S3-compatible server builds the connector
themselves and hands over the finished Client. That is what the escape
hatch is for, and it is untouched.
The CA replaces the platform trust store rather than adding to it, which is what naming a private authority means. A deployment that needs both puts both in the file.
There is no way to turn verification off; TlsConfig’s own
documentation argues that one, and the SDK’s TLS context offers no such
switch to forward even if this crate wanted to.
§Errors
If the configuration names a client certificate, if a PEM file cannot be read, or if the TLS context will not build.
Sourcepub fn from_client(
client: Client,
bucket: impl Into<String>,
key: impl Into<Keys>,
) -> Self
pub fn from_client( client: Client, bucket: impl Into<String>, key: impl Into<Keys>, ) -> Self
Uses a client the program already has.
The escape hatch, and it stays one: a connector this crate has no spelling for — mTLS, a proxy, a DNS resolver — is built here and handed over finished.
Sourcepub fn with_format(self, format: Format) -> Self
pub fn with_format(self, format: Format) -> Self
States the format, for a key whose name does not.
Required for Keys::Prefix — a prefix has no extension — and it also
settles a list whose keys name two different formats.
Sourcepub fn reporting_to(self, sink: RemoteSink) -> Self
pub fn reporting_to(self, sink: RemoteSink) -> Self
Reports this source’s watch failures to sink.
A poll loop is the half of a store dynamic-config cannot see. A
delivery keeps RemoteStatus current because
RemoteSink::apply records one — but a poll that keeps failing
delivers nothing and would otherwise say nothing: an expired
credential, a bucket policy that changed under the process, a
gateway that went away. dynamic_config_remote_up would report the
last delivery rather than the last attempt, and a bucket that
stopped answering an hour ago would look healthy until something
called refresh_remote_async().
// Taken once, where the loop is wired: a sink captures the generation
// of the source installed at that moment, which is what stops a loop
// winding down from charging its failures to its replacement.
let sink = DbConfig::remote_sink();
let watcher = S3::new("myapp-config", "prod/db.json").await?.reporting_to(sink);A failure moves the failure streak and nothing else. The fetch
count and the clock are left alone, so
dynamic_config_remote_last_fetch_seconds keeps ageing while
dynamic_config_remote_up goes to zero — the pair an alert wants.
Only the failure’s kind and key path are recorded; a bucket, an
endpoint and a key never reach a RemoteStatus.
It changes nothing about what watch returns, and
nothing about fetch, which already
records itself through refresh_remote_async().
Sourcepub fn with_timeout(self, timeout: Duration) -> Self
pub fn with_timeout(self, timeout: Duration) -> Self
How long a single fetch attempt may take before it is given up on.
The deadline for one attempt, excluding retries the underlying client performs — the sentence every store in this family answers to, and the one place in the family where the exclusion is not a technicality.
The AWS SDK retries on its own. So this maps onto
operation_attempt_timeout, which is per attempt, and a fetch can take
this multiplied by the attempt count — three, by default. That is
documented rather than tuned away: the SDK’s retry policy is a
deployment’s decision, and silently disabling it here would be this
crate overruling it. Set operation_timeout on the SdkConfig for a
ceiling on the whole call, or a retry policy for a different multiplier.
The SDK has no timeout set at all by default, so this is additive: nothing that worked before starts failing, and a fetch that used to hang now stops.
Sourcepub async fn watch<F>(
&self,
watching: &Watching,
interval: Duration,
on_change: F,
) -> Result<(), Error>
pub async fn watch<F>( &self, watching: &Watching, interval: Duration, on_change: F, ) -> Result<(), Error>
Calls on_change when the object’s ETag moves, checking every
interval.
Polling, because S3 offers nothing better without a notification
pipeline — and ETag polling, because downloading an object every
thirty seconds to discover it has not changed is a poor thing to do to a
bucket that charges per gigabyte. Each tick is a HEAD; only a new ETag
costs a GET.
The current value is not delivered at startup, for the same reason a file watcher does not report an edit when it starts. Fetch first if the starting value matters.
A failed check does not end the watch — an expired credential, a network
blip, a bucket briefly unreachable — it waits out the interval and tries
again. stop is noticed within a quarter second whatever interval is.
§What a failing loop reports
Nothing, unless reporting_to was given a sink.
With one, both failures inside the loop are reported to the
RemoteStatus as they happen: a HEAD that did not answer, and a
GET that did not answer after the ETag moved. Surviving a failure is
exactly what makes this necessary — a loop that retries forever is a
loop that reports nothing forever, and a poll silently failing since
Tuesday is indistinguishable from a configuration nobody has changed.
The refusals at the door — no format, several keys — are not reported: they are returned to the caller by this very call, before there is a loop to be silent in, and they are deployment mistakes rather than a store that stopped answering.
§Errors
If the key names no format and none was stated — a watch that cannot
parse what it fetches would poll forever and deliver nothing, so it
refuses at the start instead. If the source reads several keys: an ETag
belongs to an object, and a set of objects has none. Or if on_change
returns an error, which ends the watch. Transport failures do not
surface here; they are retried.
Trait Implementations§
Source§impl AsyncRemoteSource for S3
impl AsyncRemoteSource for S3
Auto Trait Implementations§
impl !RefUnwindSafe for S3
impl !UnwindSafe for S3
impl Freeze for S3
impl Send for S3
impl Sync for S3
impl Unpin for S3
impl UnsafeUnpin for S3
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> MaybeSendSync for T
Source§impl<T> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);