Fazer peering de clusters e SVMs

Nesta página, descrevemos como configurar o peering para o pool de armazenamento do ONTAP nos Google Cloud NetApp Volumes.

O peering de cluster e de máquina virtual de armazenamento (SVM) conectam seu pool de armazenamento do Flex Unified ONTAP a outro cluster. Isso permite que serviços como SnapMirror e FlexCache sejam executados.

Use o script peer_cluster.py para aceitar uma oferta e inserir uma senha longa para um pool no modo ONTAP. Para mais informações, consulte Script de peering de cluster.

Escolher um procedimento

Escolha um dos seguintes procedimentos de peering com base na sua configuração:

  • Peering híbrido: você migra ou replica de um pool no modo ONTAP para um volume do NetApp Volumes no modo padrão (Standard, Premium, Extreme ou Flex Unified no modo padrão). O NetApp Volumes inicia o peering no destino. Você conclui o peering no pool de origem do modo ONTAP.

  • Peering manual: você estabelece o peering por conta própria e não usa uma migração híbrida ou um fluxo de trabalho de replicação externa. Selecione um cenário:

    • Um pool no modo ONTAP e um cluster ONTAP externo local ou fora do NetApp Volumes.

    • Dois pools no modo ONTAP.

Para mais informações sobre outras opções de peering no cluster ONTAP externo, consulte a documentação do NetApp ONTAP.

Como o peering de cluster funciona em um pool no modo ONTAP

O processo de peering de cluster segue um fluxo de trabalho de oferta e aceitação:

  • Oferta: um cluster inicia o peering com os endereços IC-LIF do peer e recebe uma senha.

  • Aceitar: o cluster de peering conclui o peering usando os endereços IC-LIF e a senha do cluster de oferta.

O proxy da CLI do ONTAP não é interativo. O comando cluster peer create -generate-passphrase não solicita entrada. Por isso, é possível executar a oferta em um pool no modo ONTAP usando ontap_execute. Liste todos os endereços IC-LIF remotos como um valor -peer-addrs separado por vírgulas. O comando cluster peer accept solicita a senha, então essa etapa falha pelo proxy. Use peer_cluster.py quando um pool no modo ONTAP precisar aceitar uma oferta.

Para fazer o peering dos clusters, use um dos seguintes cenários:

  • Cenário A (ONTAP-mode e ONTAP externo): execute cluster peer create-generate-passphrase no pool do modo ONTAP usando ontap_execute com todos os endereços IC-LIF de mesmo nível. O administrador externo do ONTAP executa cluster peer accept no prompt do cluster com todos os endereços IC-LIF no modo ONTAP e insere a senha.

  • Cenário B (dois pools no modo ONTAP): execute cluster peer create-generate-passphrase no pool A usando ontap_execute, e depois execute peer_cluster.py com PEER_MODE=accept no pool B.

Faça o peering do SVM executando vserver peer accept usando ontap_execute no pool do modo ONTAP. No cenário A, o cluster ONTAP externo executa vserver peer create.

Métodos de replicação que exigem peering

Os seguintes métodos de replicação exigem peering:

  • Qualquer origem do ONTAP para o modo ONTAP unificado do Flex (SnapMirror): faça o peering no pool do modo ONTAP.

  • Flex Unified no modo ONTAP para qualquer destino ONTAP (SnapMirror): faça o peering no pool do modo ONTAP.

  • Origem no modo ONTAP para NetApp Volumes no modo padrão (migração de volume ou replicação externa): use o peering híbrido no pool de origem no modo ONTAP.

A replicação de volume no modo padrão do NetApp Volumes não usa o peering de cluster do ONTAP.

Peering híbrido

Use esta seção quando a origem for um pool no modo ONTAP e o destino for um volume no modo padrão no NetApp Volumes.

Como o NetApp Volumes funciona

O fluxo de trabalho de peering híbrido inclui as seguintes etapas:

  1. Crie uma migração de volume ou uma replicação externa no volume de destino no console do Google Cloud ou usando a Google Cloud CLI. Você especifica o nome do cluster de origem no modo ONTAP, a SVM, o volume e os endereços IC-LIF de origem.

  2. Se o peering de cluster ainda não estiver estabelecido, o NetApp Volumes verificará a conectividade no destino, gerará uma senha e mostrará instruções de peering.

  3. Você precisa realizar as etapas restantes de pareamento no pool de origem do modo ONTAP, porque o NetApp Volumes não executa comandos automatizados no pool de origem.

Não é possível reverter essa ordem. Primeiro, crie o destino no modo padrão.

Concluir o peering de cluster na origem no modo ONTAP

Recupere a senha e os endereços IC-LIF de destino no console Google Cloud na guia "Replicação" ou "Migração" ou usando a Google Cloud CLI:

 gcloud netapp volumes replications list --volume=DESTINATION_VOLUME --location=LOCATION \
  --format="table(hybridPeeringDetails.command,hybridPeeringDetails.passphrase,hybridPeeringDetails.subnetIp)"

No pool de origem no modo ONTAP, aceite o peering que o NetApp Volumes ofereceu no destino. Configure o ontap_execute conforme descrito em Procedimentos comuns no modo ONTAP. Defina POOL_NAME e LOCATION para o pool de origem. Liste todos os endereços IC-LIF de destino em PEER_IC_LIF_IPS e execute peer_cluster.py com PEER_MODE=accept:

 export PROJECT_ID="myproject"
 export LOCATION="us-central1-a"
 export POOL_NAME="ontap-mode-source-pool"
 export PEER_MODE="accept"
 export PEER_IC_LIF_IPS="DESTINATION_IC_LIF_IP_1,DESTINATION_IC_LIF_IP_2"
 export PASSPHRASE="passphrase-from-gcnv-console"

 python3 peer_cluster.py

Verifique a configuração no pool de origem:

 ontap_execute "cluster peer show"

Concluir o peering do SVM na origem do modo ONTAP

Se o NetApp Volumes não concluir o peering de SVM automaticamente, ele vai mostrar um comando de peering de vserver. Execute o comando usando ontap_execute ou aceite o peer pendente:

 ontap_execute "vserver peer accept -vserver SOURCE_SVM_NAME -peer-vserver PEER_SVM_NAME"

Para verificar a configuração:

 ontap_execute "vserver peer show"

Volte ao fluxo de trabalho híbrido no console do Google Cloud ou execute gcloud netapp volumes replications list para verificar se a replicação ou migração está em andamento.

Peering manual

Use esta seção quando você estiver estabelecendo o peering por conta própria sem um fluxo de trabalho híbrido, por exemplo, antes do SnapMirror entre um pool no modo ONTAP e um cluster ONTAP externo ou entre dois pools no modo ONTAP.

Antes de começar

Atenda aos seguintes pré-requisitos:

  1. Confirme se as IC-LIFs no pool do modo ONTAP alcançam as IC-LIFs do cluster de mesmo nível. As IC-LIFs em pools no modo ONTAP estão no IPspace Gcnv. Em clusters ONTAP externos, elas estão no IPspace Default. Teste o ICMP e as portas necessárias entre clusters.

  2. Configure o ontap_execute antes de começar.

  3. Colete o nome do cluster, o nome da SVM e todos os endereços IP de IC-LIF do cluster de mesmo nível no pool do modo ONTAP. Forneça um endereço por nó, separado por vírgula. O número de IC-LIFs corresponde à contagem de nós do cluster de mesmo nível.

  4. Compartilhe o nome do cluster e da SVM do pool e todos os endereços IC-LIF com o administrador do cluster de mesmo nível.

Visão geral

Para fazer peering manual entre clusters e SVMs, siga estas etapas:

  1. Configurar ontap_execute

  2. Pesquisar nomes e IC-LIFs

  3. Verificar a conectividade

  4. Clusters de concorrentes

  5. SVMs de concorrentes

  6. Verificar peering

Pesquisar nomes e IC-LIFs

Em cada pool no modo ONTAP, execute os comandos de pesquisa descritos em Procedimentos comuns no modo ONTAP.

Liste os endereços IC-LIF, que dependem do tamanho do pool, e forneça-os ao administrador do cluster de mesmo nível.

Verificar a conectividade

Execute um comando ping para fazer peering de IC-LIFs do seu pool usando a flag -vserver Gcnv:

 ontap_execute "network ping -vserver Gcnv -destination PEER_IC_LIF_IP -lif intercluster-1"

Corrija os problemas de roteamento ou firewall antes de continuar. Se o ping falhar entre os pools, consulte Por que seus NetApp Volumes não conseguem acessar o Active Directory (e outras redes atrás da sua VPC) para orientações sobre VPC e rede de parceiros.

Clusters de mesmo nível

Para fazer o peering dos clusters, use um dos seguintes cenários:

Cenário A: pool no modo ONTAP e ONTAP externo

Para fazer peering de um pool no modo ONTAP com um cluster ONTAP externo, siga estas etapas:

  1. Oferta no pool do modo ONTAP: execute o comando cluster peer create -generate-passphrase usando ontap_execute com todos os endereços IC-LIF de mesmo nível. Copie a senha longa da resposta ao comando.

  2. Aceitar no ONTAP externo: o administrador do cluster de mesmo nível executa o comando cluster peer accept no prompt do ONTAP com todos os endereços IC-LIF no modo ONTAP e insere a senha.

Para oferecer peering no pool do modo ONTAP:

 ontap_execute "cluster peer create -ipspace Gcnv -peer-addrs PEER_IC_LIF_1,PEER_IC_LIF_2 -generate-passphrase"

Liste todos os endereços IC-LIF do cluster de mesmo nível na flag -peer-addrs, separados por vírgulas. Adicione mais endereços se o cluster de mesmo nível tiver mais de dois nós.

O ONTAP mostra a senha na resposta ao comando em Passphrase:. Copie a senha imediatamente. O ONTAP avisa que não é possível mostrar a senha de novo.

Se o comando falhar ou a saída não incluir uma senha, use peer_cluster.py com PEER_MODE=offer. Para mais informações, consulte Script de peering de cluster.

Copie e envie a senha longa para o administrador do ONTAP externo. Aceite a oferta dentro do período de validade da senha longa, que é de uma hora por padrão.

Aceite a oferta no cluster ONTAP externo no prompt do cluster de mesmo nível listando todos os endereços IC-LIF no modo ONTAP:

 cluster peer accept -ipspace Default -peer-addrs ONTAP_MODE_IC_LIF_1,ONTAP_MODE_IC_LIF_2

Insira a senha longa quando o ONTAP solicitar. Inclua todos os endereços IC-LIF do pool no modo ONTAP.

Verifique a configuração no pool do modo ONTAP:

 ontap_execute "cluster peer show"

Cenário B: dois pools no modo ONTAP

Para fazer peering de dois pools no modo ONTAP, siga estas etapas:

  1. Oferta no pool A: execute o comando cluster peer create -generate-passphrase usando ontap_execute no pool A. Liste todos os endereços IC-LIF do pool B em -peer-addrs. Copie a senha longa.

  2. Aceitar no pool B: execute peer_cluster.py com PEER_MODE=accept no pool B e liste todos os endereços IC-LIF do pool A em PEER_IC_LIF_IPS.

Oferta no pool A:

 ontap_execute "cluster peer create -ipspace Gcnv -peer-addrs POOL_B_IC_LIF_1,POOL_B_IC_LIF_2 -generate-passphrase"

Liste todas as IC-LIF do pool B, separadas por vírgula. Adicione outros endereços quando o pool B tiver mais de dois nós. Copie o valor Passphrase: da resposta ao comando.

Se o comando falhar, use peer_cluster.py com PEER_MODE=offer no pool A.

Aceitar no pool B:

 export PROJECT_ID="myproject"
 export LOCATION="us-west1-b"
 export POOL_NAME="pool-b"
 export PEER_MODE="accept"
 export PEER_IC_LIF_IPS="POOL_A_IC_LIF_1,POOL_A_IC_LIF_2"
 export PASSPHRASE="passphrase-from-pool-a"

 python3 peer_cluster.py

Liste todas as IC-LIF do pool A em PEER_IC_LIF_IPS.

Verifique a configuração em cada pool:

 ontap_execute "cluster peer show"

Confirme se a disponibilidade é "Disponível" e se a autenticação está "OK".

SVMs de peering

Depois que o peering de cluster for concluído, crie um peer de SVM para o SnapMirror. Se você precisar do FlexCache, adicione-o à flag -applications.

Cenário A: pool no modo ONTAP e ONTAP externo

Para fazer peering de um pool no modo ONTAP com um cluster ONTAP externo, siga estas etapas:

  1. Criar no ONTAP externo: o administrador do cluster de mesmo nível executa o comando vserver peer create no prompt do ONTAP.

  2. Aceitar no pool do modo ONTAP: execute o comando vserver peer accept usando ontap_execute.

Crie o peer no cluster ONTAP externo no prompt do cluster de peer:

 vserver peer create -vserver PEER_SVM_NAME -peer-vserver ONTAP_MODE_SVM_NAME \
  -peer-cluster ONTAP_MODE_CLUSTER_NAME -applications snapmirror

Aceite o peer no pool do modo ONTAP:

 ontap_execute "vserver peer accept -vserver ONTAP_MODE_SVM_NAME -peer-vserver PEER_SVM_NAME"

Cenário B: dois pools no modo ONTAP

Para fazer peering de dois pools no modo ONTAP, siga estas etapas:

  1. Criar no pool A: execute o comando vserver peer create usando ontap_execute no pool A (ou peer_svm.py se o comando de criação não estiver disponível).

  2. Aceitar no pool B: execute o comando vserver peer accept usando ontap_execute no pool B.

Crie o peer no pool A:

 ontap_execute "vserver peer create -vserver POOL_A_SVM -peer-vserver POOL_B_SVM -peer-cluster POOL_B_CLUSTER_NAME -applications snapmirror"

Aceite o peer no pool B:

 ontap_execute "vserver peer accept -vserver POOL_B_SVM -peer-vserver POOL_A_SVM"

Não crie o mesmo peer SVM nos dois pools.

Verificar o peering

Para verificar o peering no pool do modo ONTAP:

 ontap_execute "cluster peer show"
 ontap_execute "vserver peer show"

Confirme se a disponibilidade do peer de cluster é "Available" e se o estado do peer da SVM é "peered".

Para o cenário B, repita o procedimento no segundo pool. O administrador externo do ONTAP pode verificar a configuração executando cluster peer show e vserver peer show no cluster de mesmo nível.

Quando não há peers de cluster, o comando cluster peer show retorna que a entrada não existe.

Excluir peering

Exclua os peers da SVM antes dos peers do cluster.

Para excluir um peer de SVM em um pool, exclua-o para remover a relação dos dois lados quando os pools estiverem acessíveis.

 ontap_execute "vserver peer delete -vserver LOCAL_SVM_NAME -peer-vserver PEER_SVM_NAME"

O proxy da CLI do ONTAP não é compatível com a exclusão de peers de cluster. Para excluir um cluster igual, exclua-o por UUID usando a API REST.

Primeiro, liste os peers para encontrar o UUID:

 TOKEN=$(gcloud auth print-access-token)
 curl -s -H "Authorization: Bearer $TOKEN" \

 "https://netapp.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/storagePools/POOL_NAME/ontap/api/cluster/peers"

Exclua cada UUID retornado:

 curl -s -X DELETE -H "Authorization: Bearer $TOKEN" \

 "https://netapp.googleapis.com/v1/projects/PROJECT_ID/locations/LOCATION/storagePools/POOL_NAME/ontap/api/cluster/peers/PEER_UUID"

Repita esse processo nos dois pools no modo ONTAP no cenário B. Para o cenário A, execute cluster peer delete no cluster ONTAP externo, se necessário.

Script de peering de cluster

Salve o seguinte como peer_cluster.py. Use em um pool no modo ONTAP quando ele precisar aceitar uma oferta de peering de cluster (PEER_MODE=accept). O peering híbrido e o cenário B usam o modo accept. Use o modo offer (PEER_MODE=offer) somente se cluster peer create -generate-passphrase falhar por ontap_execute ou não retornar uma senha. Esse script requer o Python 3.8 ou mais recente e a biblioteca padrão do Python.

 #!/usr/bin/env python3
"""Cluster peer offer or accept on an ONTAP-mode pool through the NetApp Volumes REST proxy."""

import json
import os
import subprocess
import sys
import time
import urllib.error
import urllib.request

REQUIRED = ("PROJECT_ID", "LOCATION", "POOL_NAME", "PEER_MODE")
missing = [name for name in REQUIRED if not os.environ.get(name)]
if missing:
    sys.exit(f"Set required environment variables: {', '.join(missing)}")

PROJECT_ID = os.environ["PROJECT_ID"]
LOCATION = os.environ["LOCATION"]
POOL_NAME = os.environ["POOL_NAME"]
PEER_MODE = os.environ["PEER_MODE"].lower()
POLL_INTERVAL = int(os.environ.get("POLL_INTERVAL", "10"))

API_ROOT = (
    f"https://netapp.googleapis.com/v1/projects/{PROJECT_ID}"
    f"/locations/{LOCATION}/storagePools/{POOL_NAME}/ontap/api"
)

def parse_ip_list(value: str) -> list:
    return [ip.strip() for ip in value.replace("#", ",").split(",") if ip.strip()]

def get_access_token() -> str:
    return subprocess.check_output(
        ["gcloud", "auth", "print-access-token"], text=True
    ).strip()

def api_request(method: str, path: str, body=None) -> dict:
    headers = {
        "Authorization": f"Bearer {get_access_token()}",
        "Content-Type": "application/json",
    }
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(f"{API_ROOT}{path}", data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(req) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as exc:
        detail = exc.read().decode()
        sys.exit(f"API request failed ({exc.code}): {detail}")

def job_record(response: dict) -> dict:
    return response.get("rawResponse") or response.get("body") or response

def job_state(response: dict) -> str:
    return job_record(response).get("state", "")

def format_job_error(response: dict) -> str:
    record = job_record(response)
    message = record.get("message") or record.get("error", {}).get("message")
    if message:
        return message
    return json.dumps(response, indent=2)

def wait_for_job(job_uuid: str) -> None:
    print(f"ONTAP job UUID: {job_uuid}")
    while True:
        response = api_request("GET", f"/cluster/jobs/{job_uuid}")
        state = job_state(response)
        print(f"  Job state: {state}")
        if state == "success":
            return
        if state in ("failure", "error"):
            sys.exit(f"Job failed: {format_job_error(response)}")
        time.sleep(POLL_INTERVAL)

def extract_passphrase(response: dict) -> str:
    body = response.get("body") or response.get("rawResponse") or {}
    records = body.get("records") or []
    if records:
        auth = records[0].get("authentication") or {}
        if auth.get("passphrase"):
            return auth["passphrase"]
    auth = body.get("authentication") or {}
    return auth.get("passphrase", "")

def build_offer_body() -> dict:
    if not os.environ.get("PEER_IC_LIF_IPS"):
        sys.exit("Set PEER_IC_LIF_IPS for offer mode")

    payload = {
        "remote": {"ip_addresses": parse_ip_list(os.environ["PEER_IC_LIF_IPS"])},
        "authentication": {"generate_passphrase": True},
        "ipspace": {"name": os.environ.get("IPSPACE", "Gcnv")},
    }

    expiry = os.environ.get("EXPIRY_TIME")
    if expiry:
        payload["authentication"]["expiry_time"] = expiry

    local_svm = os.environ.get("LOCAL_SVM_NAME")
    if local_svm:
        payload["initial_allowed_svms"] = [{"name": local_svm}]

    apps = os.environ.get("PEER_APPLICATIONS", "snapmirror")
    payload["peer_applications"] = [a.strip() for a in apps.split(",") if a.strip()]

    encryption = os.environ.get("ENCRYPTION_PROPOSED")
    if encryption:
        payload["encryption"] = {"proposed": encryption}

    return {"body": payload}

def build_accept_body() -> dict:
    for name in ("PEER_IC_LIF_IPS", "PASSPHRASE"):
        if not os.environ.get(name):
            sys.exit(f"Set {name} for accept mode")

    return {
        "body": {
            "remote": {"ip_addresses": parse_ip_list(os.environ["PEER_IC_LIF_IPS"])},
            "authentication": {"passphrase": os.environ["PASSPHRASE"]},
            "ipspace": {"name": os.environ.get("IPSPACE", "Gcnv")},
        }
    }

def main() -> None:
    if PEER_MODE == "offer":
        body = build_offer_body()
        print("Creating cluster peer offer...")
    elif PEER_MODE == "accept":
        body = build_accept_body()
        print("Accepting cluster peer offer...")
    else:
        sys.exit("PEER_MODE must be 'offer' or 'accept'")

    response = api_request("POST", "/cluster/peers?return_records=true", body)

    job = (response.get("body") or {}).get("job") or response.get("job")
    if job and job.get("uuid"):
        wait_for_job(job["uuid"])

    if PEER_MODE == "offer":
        passphrase = extract_passphrase(response)
        if passphrase:
            print(f"\nPassphrase (provide to the peer pool): {passphrase}")
        else:
            print(json.dumps(response, indent=2))

if __name__ == "__main__":
    main()

Variáveis de ambiente opcionais: EXPIRY_TIME, PEER_APPLICATIONS (padrão snapmirror), ENCRYPTION_PROPOSED e IPSPACE (padrão Gcnv).

Script de peering de SVM (reserva)

Use peer_svm.py somente quando vserver peer create não estiver disponível pelo proxy da CLI do ONTAP. Em vez disso, use vserver peer create e vserver peer accept, conforme descrito em SVMs semelhantes.

 #!/usr/bin/env python3
"""Create an SVM peer on an ONTAP-mode pool (fallback when vserver peer create is unavailable)."""

import json
import os
import subprocess
import sys
import time
import urllib.error
import urllib.request

REQUIRED = (
    "PROJECT_ID", "LOCATION", "POOL_NAME",
    "LOCAL_SVM_NAME", "PEER_CLUSTER_NAME", "PEER_SVM_NAME",
)
missing = [name for name in REQUIRED if not os.environ.get(name)]
if missing:
    sys.exit(f"Set required environment variables: {', '.join(missing)}")

PROJECT_ID = os.environ["PROJECT_ID"]
LOCATION = os.environ["LOCATION"]
POOL_NAME = os.environ["POOL_NAME"]
LOCAL_SVM_NAME = os.environ["LOCAL_SVM_NAME"]
PEER_CLUSTER_NAME = os.environ["PEER_CLUSTER_NAME"]
PEER_SVM_NAME = os.environ["PEER_SVM_NAME"]
APPLICATIONS = [
    app.strip()
    for app in os.environ.get("APPLICATIONS", "snapmirror").split(",")
    if app.strip()
]
POLL_INTERVAL = int(os.environ.get("POLL_INTERVAL", "10"))

API_ROOT = (
    f"https://netapp.googleapis.com/v1/projects/{PROJECT_ID}"
    f"/locations/{LOCATION}/storagePools/{POOL_NAME}/ontap/api"
)

def get_access_token() -> str:
    return subprocess.check_output(
        ["gcloud", "auth", "print-access-token"], text=True
    ).strip()

def api_request(method: str, path: str, body=None) -> dict:
    headers = {
        "Authorization": f"Bearer {get_access_token()}",
        "Content-Type": "application/json",
    }
    data = json.dumps(body).encode() if body is not None else None
    req = urllib.request.Request(f"{API_ROOT}{path}", data=data, headers=headers, method=method)
    try:
        with urllib.request.urlopen(req) as resp:
            return json.loads(resp.read())
    except urllib.error.HTTPError as exc:
        sys.exit(f"API request failed ({exc.code}): {exc.read().decode()}")

def format_job_error(response: dict) -> str:
    record = response.get("rawResponse") or response.get("body") or response
    message = record.get("message") or record.get("error", {}).get("message")
    return message or json.dumps(response, indent=2)

def wait_for_job(job_uuid: str) -> None:
    while True:
        response = api_request("GET", f"/cluster/jobs/{job_uuid}")
        record = response.get("rawResponse") or response.get("body") or response
        state = record.get("state", "")
        print(f"  Job state: {state}")
        if state == "success":
            print("SVM peer relationship created.")
            return
        if state in ("failure", "error"):
            sys.exit(f"Job failed: {format_job_error(response)}")
        time.sleep(POLL_INTERVAL)

def main() -> None:
    body = {
        "body": {
            "svm": {"name": LOCAL_SVM_NAME},
            "peer": {
                "cluster": {"name": PEER_CLUSTER_NAME},
                "svm": {"name": PEER_SVM_NAME},
            },
            "applications": APPLICATIONS,
        }
    }
    response = api_request("POST", "/svm/peers?return_records=true", body)
    job = (response.get("body") or {}).get("job") or response.get("job")
    if not job or not job.get("uuid"):
        print(json.dumps(response, indent=2))
        return
    wait_for_job(job["uuid"])

if __name__ == "__main__":
    main()

A seguir