# Etiquetas, user data y filtros del listado

Cada unidad tiene tres entradas que controlas tú.

| Entrada | Regla | Cuándo puede cambiar | La unidad la lee en |
|---|---|---|---|
| `key` | de 1 a 40 caracteres, forma de etiqueta DNS | nunca | variable `ZAROZ_UNIT_KEY`, `/zaroz/unit.json` |
| `labels` | como máximo 16 pares; clave `^[a-z0-9]([a-z0-9_.-]*[a-z0-9])?$` de hasta 32 caracteres; valor de hasta 64 caracteres; el mapa entero por debajo de 2 KiB | en cualquier momento | `/zaroz/unit.json` (se actualiza en vivo) |
| `user_data` | cualquier JSON, como máximo **64 KiB** y 32 niveles; `null` significa ninguno | al crear, al iniciar una unidad detenida y al asignar; cada vez **reemplaza** el valor anterior entero | `/zaroz/user-data.json` y `GET /user-data` en el socket de señales |

`user_data` **no es un almacén de secretos**. La consola lo muestra, cada lectura de la unidad lo devuelve y forma parte del objeto del clúster. Guarda los secretos en el entorno del Workload.

## Cambiar etiquetas en cualquier momento

`PATCH .../units/{key}` reemplaza el mapa de etiquetas entero. Funciona en cualquier modo de política y con unidades en marcha; la unidad ve el cambio en `/zaroz/unit.json` en aproximadamente un segundo.

**curl**

```bash
curl -sS -X PATCH "$UNITS/plot-ana" -H "$AUTH" -H "Content-Type: application/json" \
  -d '{"labels": {"kind": "plot", "owner": "ana", "tier": "free"}}'
```

**TypeScript**

```ts
await call("PATCH", `${UNITS}/plot-ana`, {
  labels: { kind: "plot", owner: "ana", tier: "free" },   // the whole map is replaced
});
```

**Python**

```python
call("PATCH", f"{UNITS}/plot-ana", {
    "labels": {"kind": "plot", "owner": "ana", "tier": "free"},  # the whole map is replaced
})
```


## Encontrar unidades por etiqueta

`GET .../units` acepta estos filtros, que se combinan con AND.

| Parámetro | Significado |
|---|---|
| `label=clave:valor` | coincidencia exacta; repítelo para varias (máximo 8); el valor puede contener dos puntos |
| `origin=policy\|code\|warm` | quién creó la unidad |
| `key_prefix=plot-` | claves que empiezan por el texto |
| `include=user_data` | añade el `user_data` de cada unidad (se omite por defecto para que la página sea pequeña; `GET .../units/{key}` siempre lo trae) |
| `include_gone=true` | incluye también las unidades retiradas en los últimos 30 días, para que sus logs sigan accesibles |

**curl**

```bash
# every unit made by your code whose labels include kind=plot AND owner=ana
curl -sS -G "$UNITS" -H "$AUTH" \
  --data-urlencode "origin=code" \
  --data-urlencode "label=kind:plot" \
  --data-urlencode "label=owner:ana" \
  --data-urlencode "key_prefix=plot-" \
  --data-urlencode "include=user_data"
```

**TypeScript**

```ts
const q = new URLSearchParams();
q.set("origin", "code");
q.append("label", "kind:plot");
q.append("label", "owner:ana");
q.set("key_prefix", "plot-");
q.set("include", "user_data");
const { body } = await call("GET", `${UNITS}?${q}`);
for (const u of body.data) console.log(u.key, u.state, u.labels);
```

**Python**

```python
status, body = call("GET", UNITS, params=[
    ("origin", "code"),
    ("label", "kind:plot"),
    ("label", "owner:ana"),
    ("key_prefix", "plot-"),
    ("include", "user_data"),
])
for u in body["data"]:
    print(u["key"], u["state"], u["labels"])
```


Las etiquetas son el lugar para lo que un matchmaker necesita para elegir una unidad (`mode:2v2`, `region:eu`, `owner:ana`). `user_data` es el lugar para lo que la propia unidad necesita para arrancar (una lista de jugadores, un trabajo, la ubicación de un mundo).
