Conecte as páginas do evento

AnsibleBeginner
Pratique Agora

Introdução

A página inicial do Riverlight Weekend está pronta, mas os visitantes não conseguem abrir a programação nem a página do local. Os dois serviços de origem já funcionam. Use o Ansible para conectar a entrada aos membros selecionados do inventário, recarregar apenas quando a configuração mudar e proteger as rotas funcionais contra uma substituição inadequada.

Você precisa de navegação básica no terminal e prática na leitura de um inventário, variáveis e um playbook pequenos do Ansible. O laboratório explica papéis HTTP, grupos, variáveis entre hosts, JSON, consultas somente de leitura e handlers antes de usá-los. Todo o software e os serviços estão preparados. O tempo é uma estimativa do autor, incluindo leitura e correções comuns.

Conecte as páginas de programação e visita

Nesta etapa, você conectará o site do evento às origens preparadas de programação e local, usando membros do inventário em vez de endereços fixos em um modelo.

O Riverlight Weekend tem uma página inicial e um guia funcionais. Os links de programação e visita mostram, por enquanto, uma mensagem de página indisponível. A entrada é um pequeno proxy reverso HTTP preparado: encaminha uma solicitação a outro serviço e devolve sua resposta real. Ela não copia os dados da programação para a página inicial. A entrada roda no controlador; os dois nós de origem são contêineres que compartilham o kernel desta VM de prática. Não são três VMs independentes. Software e serviços estão prontos; você gerencia apenas as conexões da entrada.

Abra o Tab Event Site. A página inicial deve mostrar A little closer to the river. Clique em Explore the program: This page is taking a break. é a resposta HTTP 502 esperada porque a rota ainda não está conectada. Use Back to the weekend na página e depois Visitor guide na navegação. Essa página já funciona e deve continuar disponível.

Mude para Controller, que começa em /home/labex/project. pwd mostra o diretório atual:

pwd

Se perder o diretório de trabalho, volte com cd /home/labex/project. Um nome de arquivo incorreto causa “No such file or directory”; confira a grafia, use ls templates para listar o diretório se necessário e tente novamente. Não é preciso reinicializar a VM.

cat mostra um arquivo. Leia a seleção aprovada, o inventário e os dados de cada host:

cat approved-services.txt
cat inventory.ini
cat host_vars/web1.yml
cat host_vars/web2.yml

Os grupos [program] e [venue] escolhem uma origem cada. web1 fornece a programação atual; web2 fornece o local. Os arquivos de host oferecem o service_address real e as portas dos serviços. Os endereços podem mudar entre VMs. Alguns nós também têm um serviço de arquivo histórico; estar acessível não o torna a programação atual aprovada.

O grupo [gateway] contém entry. ansible_connection=local significa que o Ansible gerencia a entrada no controlador, sem uma conexão SSH adicional. /usr/bin/python3 é o interpretador Python local preparado. Uma porta HTTP identifica um serviço que escuta em um endereço; um nó pode executar vários serviços em portas distintas.

Antes de mudar a entrada, leia diretamente cada origem selecionada. Os arquivos de configuração curl preparados contêm as URLs reais. --config lê opções de um arquivo; fail faz erros HTTP resultarem em falha, silent oculta o indicador de progresso e show-error mantém mensagens úteis. Esses arquivos não contêm senha nem token.

cat requests/web1.conf
curl --config requests/web1.conf
cat requests/web2.conf
curl --config requests/web2.conf

As respostas JSON identificam program e venue, o site riverlight e suas edições. JSON é texto estruturado com campos nomeados. Uma solicitação bem-sucedida comprova que a origem funciona diretamente, mas ainda não que as rotas do site funcionam.

Crie o modelo de rotas. groups do Ansible associa nomes de grupo aos membros; [0] escolhe o primeiro membro de um grupo que contém apenas um. hostvars recupera suas variáveis. O playbook abaixo chama esses membros de program_host e venue_host. Nas expressões Jinja, ~ une valores como texto, incluindo portas numéricas. | to_json produz uma string JSON corretamente delimitada por aspas, evitando montá-las manualmente de forma insegura.

O comando shell usa > para substituir somente este arquivo. <<'EOF' entrega as linhas seguintes literalmente ao cat; as aspas simples impedem a interpretação das chaves Jinja pelo shell. Cole até o fechamento EOF em sua própria linha. Se esquecer o delimitador e o shell ficar aguardando continuação, pressione Ctrl+C e cole novamente o comando completo.

cat > templates/routes.json.j2 <<'EOF'
{
  "program": {{ ('http://' ~ hostvars[program_host].service_address ~ ':' ~ hostvars[program_host].program_port) | to_json }},
  "venue": {{ ('http://' ~ hostvars[venue_host].service_address ~ ':' ~ hostvars[venue_host].venue_port) | to_json }}
}
EOF

Escreva o playbook da entrada. gather_facts: false evita coletar informações de máquina não utilizadas. vars define expressões avaliadas com o inventário atual. template gera o arquivo, aplica o modo 0644 (o proprietário pode escrever; todos podem ler) e notifica um handler apenas quando o arquivo de rotas muda. Um handler é uma tarefa executada após uma notificação, normalmente no fim do play.

A entrada guarda as rotas em memória; substituir só o arquivo não basta. O auxiliar preparado envia um sinal SIGHUP real apenas ao processo existente desta entrada e espera sua confirmação. O command do handler usa argv, uma lista de argumentos separados. playbook_dir é o diretório do playbook e mantém o caminho gerenciado dentro deste projeto. Você não precisa de sudo nem reiniciar o serviço.

cat > connect.yml <<'EOF'
- name: Connect the event services
  hosts: gateway
  gather_facts: false
  vars:
    program_host: "{{ groups['program'][0] }}"
    venue_host: "{{ groups['venue'][0] }}"
  tasks:
    - name: Write the inventory-derived routes
      ansible.builtin.template:
        src: templates/routes.json.j2
        dest: "{{ playbook_dir }}/entry/routes.json"
        mode: '0644'
      notify: Reload entry
  handlers:
    - name: Reload entry
      ansible.builtin.command:
        argv:
          - python3
          - /opt/labex/service-links/reload.py
          - "{{ playbook_dir }}/entry"
EOF

Verifique primeiro a estrutura YAML e depois visualize a mudança prevista. --syntax-check não aplica tarefas. --check prevê alterações compatíveis; --diff mostra o conteúdo antigo e o proposto. Essa prévia não envia sinal ao gateway nem comprova o funcionamento do site final.

ansible-playbook connect.yml --syntax-check
ansible-playbook connect.yml --check --diff

O diff deve substituir as rotas desconectadas 127.0.0.1:9 pelos endereços e portas atuais. Aplique o playbook normalmente:

ansible-playbook connect.yml

Você deve ver a alteração do modelo e RUNNING HANDLER [Reload entry]. Volte a Event Site, use Program e leia as três sessões atuais: Paper and ink, Acoustic afternoon e Shared supper. Clique em Download the schedule para baixar schedule.csv; horários, sessões e locais devem ser os mesmos da tabela. Siga Visit até Riverside Yard e depois Visitor guide. A página inicial e o guia devem continuar funcionando.

A programação conectada deve mostrar essas três sessões, com Download the schedule logo abaixo da tabela:

Programação atual do Riverlight e download dos horários

Volte a Controller. Você também pode salvar e examinar o download real dentro da VM. No curl, -f falha em erros HTTP, -sS esconde o progresso, mas mostra erros, e -o define o arquivo de saída:

curl -fsS http://127.0.0.1:8081/program/schedule.csv -o schedule.csv
cat schedule.csv

Conteúdo esperado:

time,session,place
10:30,Paper and ink,Making table
13:00,Acoustic afternoon,River stage
16:00,Shared supper,Long table

127.0.0.1 significa este controlador, onde a entrada escuta na porta 8081. O endereço público do navegador encaminha ao mesmo serviço.

Execute o mesmo playbook novamente:

ansible-playbook connect.yml

O resumo deve indicar changed=0 e failed=0, sem executar o handler. Isso é convergência: a declaração atual já corresponde ao arquivo. As páginas e o download reais comprovam o resultado utilizável; o resumo sozinho não basta.

Proteja as rotas funcionais antes de substituí-las

Nesta etapa, você adicionará verificações reais de identidade HTTP antes da escrita das rotas e rejeitará um serviço de arquivo histórico acessível preservando o site funcional.

Continue em Controller, no diretório /home/labex/project. HTTP 200 significa que o servidor respondeu com sucesso; não estabelece o tipo de serviço, evento ou edição. A programação e o local atuais se identificam por /identity. O arquivo preparado group_vars/all.yml contém o site e as edições aprovados:

cat group_vars/all.yml

Adicione uma verificação prévia, isto é, anterior à mudança. assert para o play quando uma condição é falsa. A primeira asserção exige exatamente um membro por grupo de serviço. Cada tarefa uri faz uma solicitação HTTP GET real a partir do controlador. return_content: true mantém o corpo; uma resposta JSON também fica disponível em .json. register salva o resultado sob um nome de variável para tarefas seguintes. As asserções finais comparam identidades reais com os valores aprovados.

As tarefas HTTP usam check_mode: false de propósito: essas solicitações somente de leitura devem executar também na prévia. Caso contrário, uma tarefa uri pode ser ignorada no modo de verificação. A opção pertence só às consultas de leitura; não permite aplicar um modelo ou recarregar durante a prévia. O limite de três segundos evita que uma origem ausente bloqueie o exercício por muito tempo.

Substitua o playbook por esta versão completa com verificações. Mantenha o modelo e todas as asserções de identidade antes da tarefa de modelo:

cat > connect.yml <<'EOF'
- name: Connect the event services
  hosts: gateway
  gather_facts: false
  vars:
    program_host: "{{ groups['program'][0] }}"
    venue_host: "{{ groups['venue'][0] }}"
  tasks:
    - name: Require one member for each service
      ansible.builtin.assert:
        that:
          - groups['program'] | length == 1
          - groups['venue'] | length == 1
    - name: Read the selected program identity
      ansible.builtin.uri:
        url: "http://{{ hostvars[program_host].service_address }}:{{ hostvars[program_host].program_port }}/identity"
        return_content: true
        timeout: 3
      check_mode: false
      register: program_probe
    - name: Read the selected venue identity
      ansible.builtin.uri:
        url: "http://{{ hostvars[venue_host].service_address }}:{{ hostvars[venue_host].venue_port }}/identity"
        return_content: true
        timeout: 3
      check_mode: false
      register: venue_probe
    - name: Check the actual service identities
      ansible.builtin.assert:
        that:
          - program_probe.json.service == 'program'
          - program_probe.json.site == event_site
          - program_probe.json.edition == program_edition
          - venue_probe.json.service == 'venue'
          - venue_probe.json.site == event_site
          - venue_probe.json.edition == venue_edition
    - name: Write the inventory-derived routes
      ansible.builtin.template:
        src: templates/routes.json.j2
        dest: "{{ playbook_dir }}/entry/routes.json"
        mode: '0644'
      notify: Reload entry
  handlers:
    - name: Reload entry
      ansible.builtin.command:
        argv:
          - python3
          - /opt/labex/service-links/reload.py
          - "{{ playbook_dir }}/entry"
EOF
ansible-playbook connect.yml --syntax-check

Salve agora uma impressão digital do arquivo de rotas funcional. sha256sum calcula um hash do conteúdo; > salva a saída separadamente para comparação posterior:

sha256sum entry/routes.json > routes-before.sha256

O inventário alternativo seleciona um arquivo histórico como programação. Leia-o e teste-o deliberadamente com -i, que escolhe um inventário apenas para esse comando. O inventário normal não é alterado:

cat inventory-wrong-service.ini
ansible-playbook -i inventory-wrong-service.ini connect.yml

Espera-se falha com código diferente de zero e failed=1. O arquivo histórico responde e retorna JSON, mas sua edição não está aprovada. A asserção deve falhar antes de Write the inventory-derived routes; o resumo deve mostrar changed=0, sem executar o handler. Isso difere de uma conexão recusada, na qual uri não consegue obter resposta alguma. Ambos os casos devem impedir a escrita.

Confira a impressão digital salva. -c pede ao sha256sum que compare o arquivo atual ao hash registrado:

sha256sum -c routes-before.sha256

Espere entry/routes.json: OK. Em Event Site, abra Program e baixe novamente o horário atual. Uma proposta rejeitada deve deixar a programação utilizável, não apenas um arquivo presente.

Retorne a Controller e use o inventário normal:

ansible-playbook connect.yml --check --diff
ansible-playbook connect.yml

As duas identidades escolhidas devem passar. As rotas já corretas dispensam mudanças: o resumo indica changed=0 e o handler não executa. Se surgir erro de indentação YAML, compare o bloco completo, use espaços em vez de tabulações e reescreva connect.yml. Erro de sintaxe não significa que a verificação prévia rejeitou corretamente uma origem.

Seu escopo é connect.yml, templates/routes.json.j2 e as rotas de entrada por meio desse playbook. Conserve inventários fornecidos, dados dos hosts, edições aprovadas, arquivos curl, conteúdo das origens, anotações da organização, página inicial e guia. Use /opt/labex/service-links/reload.py com o diretório de entrada deste projeto para recarregar. Não fixe nomes ou endereços atuais no modelo ou nas consultas, não copie páginas de origem para a entrada, não oculte falhas, não reinicie os nós de origem nem edite o gateway preparado. Os membros e portas configurados devem continuar determinando a conexão quando o inventário mudar.

Resumo

Você conectou serviços reais de programação e local por rotas derivadas do inventário, examinou o site e seu download CSV exato e usou um handler para recarregar somente configurações alteradas. Depois rejeitou uma origem acessível, mas não aprovada, antes da escrita das rotas, preservando o site atual. O próximo laboratório independente muda os membros e mantém a origem anterior e seus dados.