Actualiza un recurso con una máscara de campo

Cuando actualizas un recurso en Google Cloud, a menudo quieres modificar campos específicos sin reemplazar todo el recurso. Las bibliotecas cliente de Cloud para Rust admiten máscaras de campo para que puedas especificar qué campos modifica una operación de actualización y dejar todos los demás campos sin cambios.

Antes de comenzar

En este documento, se usa la API de Secret Manager, aunque los mismos conceptos se aplican a otros servicios de Google Cloud .

Antes de ejecutar el código de este documento, completa los siguientes requisitos previos:

Dependencias

El cajón google-cloud-wkt proporciona tipos conocidos para las APIs de Google Cloud, incluido FieldMask. Agrega google-cloud-secretmanager-v1, google-cloud-wkt, anyhow y tokio a tu archivo Cargo.toml:

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

Cómo funcionan las máscaras de campo

Un FieldMask contiene un conjunto de rutas de acceso de campos simbólicos que identifican qué campos modifica una operación de actualización o qué campos devuelve una operación de lectura.

En una operación de actualización, el servicio cambia solo los campos que se indican en la máscara y omite los valores de los campos que no se indican en el mensaje de solicitud. Si omites la máscara de campo en una solicitud de actualización, la operación se aplica a todos los campos mutables.

Para restablecer un campo específico a su valor predeterminado, incluye la ruta de acceso del campo en la máscara y deja ese campo en su valor predeterminado en la estructura del recurso.

Actualiza los campos de un recurso

Para crear un Secret y actualizar de forma selectiva sus campos labels y annotations con un FieldMask, completa los siguientes pasos:

  1. Inicializa un cliente SecretManagerService y crea un secreto con labels y annotations vacíos:

    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. Envía una solicitud update_secret que establezca labels, annotations, el etag actual para evitar que se reemplacen las actualizaciones simultáneas y una máscara de actualización que abarque "annotations" y "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:?}");

    La llamada set_update_mask especifica las rutas de campo exactas que se deben modificar:

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

El resultado confirma que la operación actualizó ambos campos:

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

Completar código

La siguiente función combina la creación de secretos y la actualización de la máscara de campo:

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

Realiza una limpieza

Para evitar que se apliquen cargos a tu cuenta de Google Cloud y evitar errores deALREADY_EXISTSen ejecuciones posteriores, borra el secreto your-secretcuando termines.