フィールド マスクを使用してリソースを更新する

フィールド マスクを使用してリソースを選択的に更新する方法を説明します。 でリソースを更新する場合、リソース全体を置き換えるのではなく、特定のフィールドのみを変更したいことがあります。 Google CloudRust クライアント ライブラリはフィールド マスクをサポートしているため、リソースのどのフィールドを更新し、どのフィールドを変更しないかを正確に制御できます。

前提条件

このガイドでは Secret Manager API を使用しますが、このコンセプトは 他の Google Cloud リソースやサービスにも適用されます。

続行する前に、 Secret Manager を使用してシークレットを作成してアクセスする の手順に沿って、Secret Manager API を有効にして認証します。

Rust ライブラリの設定手順については、 開発環境の設定をご覧ください。

依存関係

Secret Manager を有効にしたら、Cargo.toml ファイルで依存関係を宣言します。

cargo add google-cloud-secretmanager-v1
cargo add tokio

既知のタイプをインストールする

google_cloud_wkt クレートには、 Google Cloud API の既知のタイプが含まれています。 これらのタイプには通常、カスタム JSON エンコードがあり、一般的に使用される Rust タイプとの間で変換を行う関数が用意されています。google_cloud_wkt クレートには、フィールド マスクタイプ FieldMask が含まれています。

クレートを依存関係として追加します。

cargo add google-cloud-wkt

フィールド マスク

FieldMask は、一連のシンボリック フィールド パスを表します。フィールド マスクは、更新オペレーションで変更されるフィールドまたは get オペレーションで返されるフィールドのサブセットを指定します。

更新オペレーションでは、フィールド マスクは、ターゲット リソースのどのフィールドを更新するかを指定します。 API は、マスクで指定されたフィールドの値のみを変更し、他のフィールドは変更しません。更新された値を記述するリソースを渡すと、 API はマスクでカバーされていないすべてのフィールドの値を無視します。更新時にフィールド マスクを指定しない場合、オペレーションはすべてのフィールドに適用されます。

フィールドをデフォルト値にリセットするには、マスクにフィールドを含め、指定されたリソースにデフォルト値を設定します。リソースのすべてのフィールドをリセットするには、リソースのデフォルト インスタンスを指定して、マスク内のすべてのフィールドを設定するか、マスクを指定しません。

リソースのフィールドを更新する

まず、Secret Manager クライアントを初期化してシークレットを作成します。

    let client = SecretManagerService::builder().build().await?;

    let secret = client
        .create_secret()
        .set_parent(format!("projects/{project_id}"))
        .set_secret_id("your-secret")
        .set_secret(
            Secret::new().set_replication(Replication::new().set_automatic(Automatic::new())),
        )
        .send()
        .await?;
    println!("CREATE = {secret:?}");

作成オペレーションの出力には、labels フィールドと annotations フィールドの両方が空であることが示されています。

次のコードは、labels フィールドと annotations フィールドを更新します。

    let tag = |mut labels: HashMap<_, _>, msg: &str| {
        labels.insert("updated".to_string(), msg.to_string());
        labels
    };

    let update = client
        .update_secret()
        .set_secret(
            Secret::new()
                .set_name(&secret.name)
                .set_etag(secret.etag)
                .set_labels(tag(secret.labels, "your-label"))
                .set_annotations(tag(secret.annotations, "your-annotations")),
        )
        .set_update_mask(FieldMask::default().set_paths(["annotations", "labels"]))
        .send()
        .await?;
    println!("UPDATE = {update:?}");

set_etag メソッドを使用すると、シークレットに etag を設定して、同時更新の上書きを防ぐことができます。

更新されたシークレットにラベルとアノテーションを設定したら、フィールド マスクを set_update_mask に渡して、更新するフィールド パスを指定します。

        .set_update_mask(FieldMask::default().set_paths(["annotations", "labels"]))

更新オペレーションの出力には、フィールドが更新されたことが示されています。

labels: {"updated": "your-label"},
...
annotations: {"updated": "your-annotations"},

フィールドを更新する: 完全なコード

このサンプルコードでは、シークレットを初期化して作成し、フィールド マスクを適用します。

use google_cloud_secretmanager_v1::client::SecretManagerService;
use google_cloud_secretmanager_v1::model::replication::Automatic;
use google_cloud_secretmanager_v1::model::{Replication, Secret};
use google_cloud_wkt::FieldMask;
use std::collections::HashMap;

pub async fn sample(project_id: &str) -> anyhow::Result<()> {
    let client = SecretManagerService::builder().build().await?;

    let secret = client
        .create_secret()
        .set_parent(format!("projects/{project_id}"))
        .set_secret_id("your-secret")
        .set_secret(
            Secret::new().set_replication(Replication::new().set_automatic(Automatic::new())),
        )
        .send()
        .await?;
    println!("CREATE = {secret:?}");

    let tag = |mut labels: HashMap<_, _>, msg: &str| {
        labels.insert("updated".to_string(), msg.to_string());
        labels
    };

    let update = client
        .update_secret()
        .set_secret(
            Secret::new()
                .set_name(&secret.name)
                .set_etag(secret.etag)
                .set_labels(tag(secret.labels, "your-label"))
                .set_annotations(tag(secret.annotations, "your-annotations")),
        )
        .set_update_mask(FieldMask::default().set_paths(["annotations", "labels"]))
        .send()
        .await?;
    println!("UPDATE = {update:?}");

    Ok(())
}