YAML e Configurações de Automação de Rede


Quando trabalhamos com arquivos YAML para armazenar configurações de dispositivos de rede, é comum nos depararmos com um problema: strings multilinha que representam comandos são carregadas como uma única string sem quebras de linha. Isso pode gerar dificuldades ao aplicar essas configurações em dispositivos usando ferramentas como o Netmiko, que esperam comandos separados por quebras de linha. Neste artigo, vamos explorar esse problema e apresentar uma solução simples usando o estilo literal do YAML.
O Problema
Vamos analisar o seguinte trecho de um arquivo YAML, que define a configuração de um dispositivo de rede:
R1:
conn:
host: clab-ospf_foundations__ospf_broadcast-r1
device_type: cisco_ios
username: admin
password: autonetops
port: 22
config:
interface Ethernet0/1
ip address 100.100.100.1 255.255.255.0
!
interface Tunnel1234
ip address 10.1.1.1 255.255.255.0
no ip redirects
ip nhrp map 10.1.1.2 100.100.100.2
ip nhrp map 10.1.1.3 100.100.100.3
ip nhrp map 10.1.1.4 100.100.100.4
ip nhrp network-id 111
ip ospf network broadcast
ip ospf priority 100
tunnel source Ethernet0/1
tunnel mode gre multipoint
!
interface Loopback0
ip address 1.1.1.1 255.255.255.255
ip ospf network point-to-point
!
router ospf 1
network 1.1.1.1 0.0.0.0 area 0
network 10.1.1.0 0.0.0.255 area 0
Ao carregar esse YAML em Python usando yaml.safe_load, a seção config é interpretada como uma única string, com as quebras de linha substituídas por espaços:
'interface Ethernet0/1 ip address 100.100.100.1 255.255.255.0 ! interface Tunnel1234 ...'
Isso se torna um problema quando tentamos mandar as configurações para um roteador com netmiko por exemplo:
from netmiko import ConnectHandler
### LOAD YAML CODE INTO A VARIABLE
device = yaml.safe_load(file_path)
conn = ConnectHandler(**device['R1']['conn'])
conn.send_config_set(device['R1']['config'])
## Esse código irá retornar um erro, pois não há quebra de linhas
## E nós não conseguimos quebrar em vários comandos, pois não há quebra de linhas
Essa string "compactada" não é adequada para ferramentas de automação de rede, pois elas não conseguem identificar os comandos individuais sem as quebras de linha.
A Solução
Para preservar as quebras de linha na string de configuração, podemos usar o estilo literal do YAML, adicionando o símbolo de pipe (|) após a chave config:. Isso instrui o parser YAML a manter o texto exatamente como foi escrito, incluindo quebras de linha e indentação. Veja o YAML corrigido:
R1:
conn:
host: clab-ospf_foundations__ospf_broadcast-r1
device_type: cisco_ios
username: admin
password: autonetops
port: 22
config: |
interface Ethernet0/1
ip address 100.100.100.1 255.255.255.0
!
interface Tunnel1234
ip address 10.1.1.1 255.255.255.0
no ip redirects
ip nhrp map 10.1.1.2 100.100.100.2
ip nhrp map 10.1.1.3 100.100.100.3
ip nhrp map 10.1.1.4 100.100.100.4
ip nhrp network-id 111
ip ospf network broadcast
ip ospf priority 100
tunnel source Ethernet0/1
tunnel mode gre multipoint
!
interface Loopback0
ip address 1.1.1.1 255.255.255.255
ip ospf network point-to-point
!
router ospf 1
network 1.1.1.1 0.0.0.0 area 0
network 10.1.1.0 0.0.0.255 area 0
Agora, ao carregar com yaml.safe_load, a seção config mantém suas quebras de linha:
"interface Ethernet0/1\n ip address 100.100.100.1 255.255.255.0\n !\ninterface Tunnel1234\n ip address 10.1.1.1 255.255.255.0\n no ip redirects\n..."
Essa string multilinha pode ser facilmente dividida em comandos individuais, tornando-a compatível com ferramentas como o Netmiko.
from netmiko import ConnectHandler
### LOAD YAML CODE INTO A VARIABLE
device = yaml.safe_load(file_path)
def convert_yaml_to_commands(config):
"""Convert YAML config to list of commands"""
commands = []
for line in config.split('\n'):
line = line.strip()
commands.append(line.lstrip())
return commands
conn = ConnectHandler(**device['R1']['conn'])
commands = convert_yaml_to_commands(config)
conn.send_config_set(commands)
## Esse código irá retornar um erro, pois não há quebra de linhas
## E nós não conseguimos quebrar em vários comandos, pois não há quebra de linhas
Por Que Isso Funciona?
Comportamento Padrão: Sem o |, o YAML utiliza o estilo "folded" (compactado), substituindo quebras de linha por espaços.
Estilo Literal: O | garante que as quebras de linha e a indentação sejam preservadas, mantendo a estrutura da configuração.
Uma Abordagem Alternativa
Outra opção é estruturar a seção config como uma lista de comandos, usando hífens (-):
R1:
conn:
# ... detalhes de conexão ...
config:
- interface Ethernet0/1
- ip address 100.100.100.1 255.255.255.0
- !
- interface Tunnel1234
# ... e assim por diante
Isso será carregado como uma lista em Python, o que pode ser útil para algumas ferramentas de automação. No entanto, essa abordagem perde a hierarquia de indentação, o que pode dificultar a leitura ou impactar a funcionalidade em certos cenários.
Conclusão
Para configurações de rede em YAML, adicionar o símbolo | para usar o estilo literal é uma solução simples e eficaz para preservar quebras de linha e indentação. Isso garante que os comandos sejam carregados corretamente e estejam prontos para automação, sendo a abordagem mais indicada para configurações hierárquicas como a apresentada. Boa automação!
Subscribe to my newsletter
Read articles from pDamasceno directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
