Dateien mit Rust nach Microsoft Azure exportieren
Laden Sie mit diesem vollständigen Rust-Programm eine lokale Datei mit bis zu 16 MiB in einen vorhandenen privaten Azure-Blob-Storage-Container hoch. Es sendet eine bedingte Anfrage und weigert sich, ein vorhandenes Blob zu ersetzen. Leere Dateien und Binärdaten sind gültige Eingaben.
Dieses Beispiel dient der Wartung bestehender Anwendungen mit der inoffiziellen Crate
azure_storage_blobs 0.21.0.
Microsoft erklärt im Hinweis zur Legacy-Crate,
dass keine Aktualisierungen dieser Crate geplant sind. Prüfen Sie für neue Anwendungen das
offizielle SDK azure_storage_blob,
dessen Authentifizierungsbeispiele Microsoft Entra ID verwenden. Seine API unterscheidet sich von
diesem Beispiel mit festgelegter Version; allein den Abhängigkeitsnamen zu ändern, ist keine Migration.
Voraussetzungen
- Eine Linux-Shell mit Bash, Rust, Cargo und dem für Ihre Rust-Installation erforderlichen System-Linker. Dieses Beispiel wurde mit Rust und Cargo 1.98.1 unter Verwendung der Edition 2021 getestet. Das beschreibt die getestete Umgebung, keine Mindestversion des Compilers. Wie Sie eine aktuelle Toolchain installieren, erklärt die Rust-Installationsanleitung.
- Ein C-Compiler,
pkg-configsowie OpenSSL-Bibliotheken und Header. Der standardmäßige TLS-Transport benötigt diese unter Linux; die Build-Anleitung der OpenSSL-Crate nennt die Pakete für gängige Distributionen. Installieren Sie diese Voraussetzungen, bevor Sie das Projekt erstellen. - Ein Azure-Storage-Konto, das die Shared-Key-Authentifizierung bereits zulässt, sowie dessen Kontoname und Zugriffsschlüssel. Dieser Ansatz ist für eine bestehende Shared-Key-Integration gedacht. Microsoft empfiehlt Microsoft Entra ID für neue Anwendungen; aktivieren Sie Shared Key nicht eigens für dieses Beispiel.
- Ein vorhandener privater Container, der separat bereitgestellt wurde. Das Programm erstellt keine Container und ändert deren Zugriffseinstellungen nicht. Zum Lesen der Blobs in einem privaten Container ist eine Autorisierung erforderlich, wie in der Azure-Dokumentation zum anonymen Zugriff beschrieben.
- Eine vollständige reguläre Datei, die während des Uploads unverändert bleibt. Befehlsargumente, einschließlich des lokalen Pfads, müssen gültiges UTF-8 sein. Führen Sie Uploads mit diesem Beispiel nacheinander aus.
Projekt einrichten
Führen Sie den folgenden Block in einem beschreibbaren Verzeichnis aus. Er prüft die Build-Werkzeuge
und erstellt ein neues Verzeichnis. Falls azure_export bereits existiert, bricht er
ab, ohne dieses Projektverzeichnis zu betreten oder das Projekt zu ändern.
(
command -v cargo >/dev/null &&
command -v rustc >/dev/null &&
command -v cc >/dev/null &&
command -v pkg-config >/dev/null &&
pkg-config --exists openssl &&
mkdir azure_export &&
mkdir azure_export/src
) && cd azure_export
Fahren Sie erst fort, wenn das erfolgreich war. Speichern Sie Folgendes als
Cargo.toml. Mit dem leeren Eintrag [workspace] bleibt dieses
Projekt von einem übergeordneten Cargo-Workspace getrennt. Die Dateisystem- und I/O-Features von Tokio
sind explizit angegeben. Bewahren Sie die generierte Datei Cargo.lock bei Ihrer
Anwendung auf, um die aufgelösten transitiven Abhängigkeiten beizubehalten.
Falls die Verzeichniserstellung unterwegs fehlschlägt, prüfen Sie vor einem erneuten Versuch, was bereits erstellt wurde. Verwenden Sie für einen neuen Versuch ein neues beschreibbares Elternverzeichnis; der Block erhält vorhandene Dateien bewusst.
[package]
name = "azure_export"
version = "0.1.0"
edition = "2021"
[workspace]
[dependencies]
azure_core = "=0.21.0"
azure_storage = "=0.21.0"
azure_storage_blobs = "=0.21.0"
tokio = { version = "=1.48.0", features = ["fs", "io-util", "macros", "rt-multi-thread", "time"] }
Azure-Client initialisieren
Stellen Sie AZURE_STORAGE_ACCOUNT und AZURE_STORAGE_KEY über Ihren Secret-Manager
oder die Prozessumgebung bereit. Der Schlüssel ist ein Zugriffsschlüssel für das Storage-Konto,
keine Verbindungszeichenfolge. Das Programm ruft StorageCredentials::access_key() auf; es übernimmt keine
Anmeldung aus der Azure CLI. Halten Sie den Schlüssel aus der Versionsverwaltung und aus
Befehlsargumenten im Terminal fern.
Speichern Sie das vollständige Programm unten als src/main.rs.
Datei-Upload implementieren
Das Programm liest höchstens 16 MiB plus ein Byte, bevor es eine Anfrage sendet, und weist zu große
Eingaben zurück. Die Obergrenze von 16 MiB ist eine Vorgabe dieses Beispiels, keine Speichergrenze
von Azure. Es puffert die Eingabe für einen Vorgang mit put_block_blob; es teilt die
Datei weder in separat bereitgestellte Blöcke auf noch lädt es sie parallel hoch. Der Name des
Ziel-Blobs wird als separates Argument neben dem lokalen Pfad übergeben.
use azure_core::{prelude::IfMatchCondition, RetryOptions};
use azure_storage::StorageCredentials;
use azure_storage_blobs::prelude::{BlobServiceClient, ClientBuilder};
use std::{env, error::Error, path::Path, time::Duration};
use tokio::{fs::File, io::AsyncReadExt, time::timeout};
type AppResult<T> = Result<T, Box<dyn Error + Send + Sync>>;
const MAX_BYTES: u64 = 16 * 1024 * 1024;
async fn upload_file(
service: &BlobServiceClient,
container: &str,
blob_name: &str,
path: &Path,
) -> AppResult<()> {
if container.is_empty() || blob_name.is_empty() {
return Err("Container and blob name must not be empty".into());
}
let file = File::open(path).await?;
if !file.metadata().await?.is_file() {
return Err("Input must be a regular file".into());
}
let mut contents = Vec::new();
file.take(MAX_BYTES + 1).read_to_end(&mut contents).await?;
if contents.len() as u64 > MAX_BYTES {
return Err("Input exceeds the 16 MiB example limit".into());
}
let blob = service.container_client(container).blob_client(blob_name);
blob.put_block_blob(contents)
.content_type("application/octet-stream")
.if_match(IfMatchCondition::NotMatch("*".to_owned()))
.await?;
Ok(())
}
async fn run() -> AppResult<()> {
let args: Vec<String> = env::args().skip(1).collect();
if args.len() != 3 {
return Err("Usage: azure_export CONTAINER BLOB_NAME FILE".into());
}
let account = env::var("AZURE_STORAGE_ACCOUNT")?;
let key = env::var("AZURE_STORAGE_KEY")?;
let credentials = StorageCredentials::access_key(account.clone(), key);
let service = ClientBuilder::new(account, credentials)
.retry(RetryOptions::none())
.blob_service_client();
timeout(
Duration::from_secs(60),
upload_file(&service, &args[0], &args[1], Path::new(&args[2])),
)
.await??;
println!("Upload confirmed.");
Ok(())
}
#[tokio::main]
async fn main() {
if run().await.is_err() {
eprintln!("Upload was not confirmed; check the input, credentials, container, and destination.");
std::process::exit(1);
}
}
Legen Sie die zu exportierende Datei unter data.bin im Projektverzeichnis ab.
Wenn die Zugangsdaten bereitstehen und der private Container rust-exports bereits
vorhanden ist, führen Sie Folgendes aus:
cargo run -- rust-exports 'exports/data.bin' './data.bin'
Cargo löst die Abhängigkeiten auf, kompiliert das Programm und führt es aus. Die drei Argumente sind
der Container, der Name des Ziel-Blobs und der lokale Dateipfad. Setzen Sie Pfade mit Leerzeichen in
Anführungszeichen. Bei einer erfolgreichen Anfrage gibt das Programm Upload confirmed.
aus und beendet sich mit dem Exit-Code null. Das Blob heißt exports/data.bin; der
Schrägstrich ist Teil seines Namens, unabhängig von Ihrer lokalen Verzeichnisstruktur. Wählen Sie
einen Blob-Namen ohne führende oder abschließende Schrägstriche: Dieses SDK entfernt diese Zeichen.
Die Frist von 60 Sekunden umfasst das Lesen der lokalen Datei und den Upload durch das SDK nach der Client-Erstellung. Die Installation der Abhängigkeiten und die Kompilierung durch Cargo liegen außerhalb dieser Frist. Auch eine Datei unterhalb der Größenobergrenze kann diese Frist bei einer langsamen Verbindung überschreiten.
Fehler behandeln
Ein lokaler Lesefehler, eine fehlende Konfiguration, eine abgewiesene Anfrage oder eine
Zeitüberschreitung führt zu einem Exit-Code ungleich null und der allgemeinen Diagnosemeldung
Upload was not confirmed. Das Programm gibt bewusst keine Zugangsdaten oder unverarbeiteten
SDK-Antworten aus. Prüfen Sie zuerst die lokale Datei und ihre Größe, dann das ausgewählte Konto,
den Schlüssel, den Container und das Ziel. Diese Diagnosemeldung allein nennt weder den Grund für
die Ablehnung durch Azure noch beweist sie, dass kein Blob geschrieben wurde.
Die Option IfMatchCondition::NotMatch("*") sendet If-None-Match: *. Die
Azure-Spezifikation für bedingte Header
erlaubt das Schreiben nur, wenn das Ziel nicht existiert. Ein erneuter Aufruf des Befehls für ein
vorhandenes Ziel schlägt fehl und erhält dessen bisherigen Inhalt. Wählen Sie für einen neuen
Export einen anderen Blob-Namen, statt ein vorhandenes Objekt zu löschen, damit der Befehl gelingt.
SDK-Retries sind deaktiviert. Nach einer Zeitüberschreitung, einem Verbindungsverlust oder einer Unterbrechung kann Azure einen bereits empfangenen Upload noch abschließen. Das Beenden des lokalen Prozesses bricht diesen entfernten Schreibvorgang nicht ab. Versuchen Sie es nicht blind erneut und werten Sie eine leere Auflistung nicht als Beweis dafür, dass ein ausstehender Schreibvorgang nicht später sichtbar werden kann. Prüfen Sie das genaue Ziel mit einem authentifizierten Client und klären Sie den Zustand des ersten Vorgangs, bevor Sie ihn erneut versuchen. Eine spätere Ablehnung kann bedeuten, dass der erste Upload erfolgreich war.
Gespeichertes Ergebnis prüfen
Upload confirmed. bedeutet, dass das SDK eine erfolgreiche Upload-Antwort erhalten hat.
Das Programm lädt das Blob nicht herunter und vergleicht die gespeicherten Bytes nicht. Wenn Sie
einen Export verifizieren müssen, laden Sie genau dieses Blob mit einem authentifizierten Client
herunter und vergleichen Sie die gesamte heruntergeladene Datei mit der unveränderten Quelldatei,
auch bei einer Quelldatei mit null Byte. Allein den Namen oder die Byteanzahl zu prüfen, erkennt
keinen abweichenden Inhalt gleicher Größe. Bewahren Sie die lokale Quelldatei auf, bis die Prüfung
abgeschlossen ist.
Die private Zugriffseinstellung des Containers ist eine separate Voraussetzung: Ein erfolgreicher Upload bestätigt seine Zugriffsrichtlinie nicht. Dieses Beispiel bietet weder fortsetzbare Uploads noch eine Transferüberwachung für den Produktionseinsatz. Beginnen Sie für größere Dateien oder identitätsbasierte Authentifizierung mit den Upload- und Zugangsdatenbeispielen des offiziellen SDKs, statt die festgelegten Legacy-Versionen ohne Prüfung der Migration weiterzuverwenden.
