使用字段掩码更新资源

在 Google Cloud中更新资源时,您通常希望修改特定字段,而不是替换整个资源。Rust 版 Cloud 客户端库支持字段掩码,因此您可以指定更新操作要修改哪些字段,并让所有其他字段保持不变。

准备工作

本文档使用 Secret Manager API,但这些概念同样适用于其他 Google Cloud 服务。

在运行本文档中的代码之前,请先完成以下前提条件:

依赖项

google-cloud-wkt crate 为 Google CloudAPI 提供了一些众所周知的类型,包括 FieldMask。将 google-cloud-secretmanager-v1、google-cloud-wkt、anyhow 和 tokio 添加到 Cargo.toml 文件中:

cargo add google-cloud-secretmanager-v1 google-cloud-wkt anyhow
cargo add tokio --features macros,rt-multi-thread

字段掩码的工作原理

FieldMask 包含一组符号字段路径,用于标识更新操作修改或读取操作返回的字段。

在更新操作中,服务仅更改掩码中列出的字段,并忽略请求消息中任何未列出字段的值。如果您在更新请求中省略了字段掩码,则该操作会应用于所有可变字段。

如需将特定字段重置为其默认值,请在掩码中包含字段路径,并将该字段保留在资源结构的默认值。

更新资源上的字段

如需创建 Secret 并使用 FieldMask 选择性地更新其 labels 和 annotations 字段,请完成以下步骤:

  1. 初始化 SecretManagerService 客户端,并使用空的 labels 和 annotations 创建 Secret:

    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:?}");

  2. 发送 update_secret 请求,设置 labels、annotations、当前 etag(以防止覆盖并发更新),以及涵盖 "annotations" 和 "labels" 的更新掩码:

    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_update_mask 调用指定要修改的确切字段路径:

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

输出结果确认该操作更新了这两个字段:

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

完整代码

以下函数结合了 Secret 创建和字段掩码更新:

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(())
}

清理

为避免系统向您的 Google Cloud 账号收取费用,并防止在后续运行中出现 ALREADY_EXISTS 错误,请在完成后删除 your-secret 密钥。