12 de mai. de 2018

YAML e JINJA2 - Parte I

Olá Pessoal Boa Noite, hoje vamos falar um pouco sobre templates e criação automática de configurações.

YAML são as iniciais de Yet Another Markup Language, o objetivo inicial de YAML foi o de poder transformar estruturas de dados em um formato que possa ser armazenado em arquivos, ou enviado via rede para outras máquinas; da mesma forma que XML.

A diferença de XML, YAML é mais intuitivo fazendo que sua escrita e leitura sejam mais fáceis de entender.

Devido à essa facilidade na leitura e escrita, YAML é amplamente utilizado na definição de configurações. Por exemplo se eu quiser definir um roteador que vai precisar executar "bgp", eu posso colocar todas essas definições em um arquivo, YAML. Esse arquivo posteriormente pode se utilizado por outro software como JINJA2, para gerar arquivos de configurações, podendo inclusive, com ajuda de templates JINJA2, gerar configurações para diferentes fabricantes.



Os arquivos YAML precisam ser processados por um "parser", esse parser se encarrega de ler o arquivo YAM e criar uma estrutura de dados a qual possamos acessar. Em Python esse parser é feito pela livraria PyYAML

Antes de continuar com YAML, vou lhes mostrar alguns conceitos sobre estruturas de dados aninhados em python, isso vai ajudar no entendimento da sintaxes YAML.

Diccionarios Aninhados


Até agora conhecemos os diccionarios em python, porém nada impede ter diccionarios dentro de diccionarios. Exemplo:

Roteadores={'R1':{'hostname':'R1SP','ip':'1.1.1.1'},'R2':{'hostname':'R1SP','ip':'1.1.1.1'}}

O diccionario acima "Roteadores", tem duas chaves, a primeira chave 'R1' e a segunda 'R2'. O detalhe é que o valor associado à chave 'R1' é um outro diccionario, o mesmo para 'R2'.

Vamos testar no interpretador de python:


>>> Roteadores={'R1':{'hostname':'R1SP','ip':'1.1.1.1'},'R2':{'hostname':'R1SP','ip':'1.1.1.1'}}
>>> Roteadores
{'R1': {'ip': '1.1.1.1', 'hostname': 'R1SP'}, 'R2': {'ip': '1.1.1.1', 'hostname': 'R1SP'}}
>>> Roteadores['R1']
{'ip': '1.1.1.1', 'hostname': 'R1SP'}
>>> Roteadores['R2']
{'ip': '1.1.1.1', 'hostname': 'R1SP'}
>>> Roteadores['R1']['ip']
'1.1.1.1'
>>> Roteadores['R2']['ip']
'1.1.1.1'
>>> 

Para poder ir digamos assim acessando aos valores de diccionarios mais baixos podemos utilizar a notação Diccionario_Pai[chave-1][chave-2]...[chave-n].


Listas de Diccionarios

Ao igual que existem diccionarios aninhados, nada impede ter por exemplo uma lista de diccionarios. Vejamos:

>>> Roteadores=[{'hostname':'R1SP','ip':'1.1.1.1'},{'hostname':'R1SP','ip':'1.1.1.1'}]
>>> Roteadores
[{'ip': '1.1.1.1', 'hostname': 'R1SP'}, {'ip': '1.1.1.1', 'hostname': 'R1SP'}]
>>> Roteadores[0]
{'ip': '1.1.1.1', 'hostname': 'R1SP'}
>>> Roteadores[1]
{'ip': '1.1.1.1', 'hostname': 'R1SP'}
>>> Roteadores[0]['ip']
'1.1.1.1'
>>> Roteadores[1]['ip']
'1.1.1.1'
>>> 

Agora o acesso aos elementos do diccionario é um pouco diferente, utilizamos uma combinação do index da lista e a chave do diccionario.

Ao momento de processar um arquivo YAML para poder utilizar ele em JINJA2 p.e, vamos utilizar bastante as estruturas acima mostradas.

Instalação do módulo PyYAML para parseamento


Para parsear os arquivos YAML é preciso instalar o módulo pyyaml.

sudo pip install pyyaml

E para utilizar basta importar o módulo em nosso interpretador python

import yaml



Agora sim ...Continuando com YAML.....


Sintaxes em YAML


Inicio de um Documento

Se utiliza o string '---' para indicar o inicio de um documento YAML.

Fim de um Documento

Se utiliza o string '...' para indicar o fim de um documento YAML.

Podem ser inseridos vários documentos em um único arquivo YAML.

Indentação

YAML utiliza indentação para definir hierarquias, similar a indentação em python. Exemplo:

R1:
  hostname: R1SP

No exemplo acima a chave "hostname", com valor "R1SP" esta embaixo da chave "R1". Existe uma hierarquia em YAML.

Em python a configuração acima pode ser traduzida para o seguinte diccionario:

{'R1':{'hostname':'R1SP'}}

Separador

Em YAML somente se utiliza "espaço" como separador, nada de TAB.


Escalares

YAML, permite a definição de diferentes tipos de variavéis, inteiro, float, string boolean. A forma como é definido é do tipo "chave:valor". O tipo de variavél é reconhecido automáticamente.

myInteiro: 10
myFloat: 3.14
myString: "Post de YAML"

Em python a configuração acima se traduz para:

{'myInteiro': 10, 'myFloat': 3.14, 'myString': 'Post de YAML'}

Strings podem estar entre aspas simples o duplas. Se utilizam duplas quando precisamos utilizar caracteres especiais nesse caso também utilizamos o caractere "\"

myString: "Primeira Linha\nSegunda Linha" 

As vezes precisamos armazenar um string de forma literal nesse caso podemos utilizar o operador '|':

myString: |
  "Post de YAML
  exemplo de string.

  Novo paragrafo"

Em python a configuração acima se traduz em:   

{'myString': '"Post de YAML\n exemplo de string.\n Novo paragrafo"\n'}

é possivél também indicar em YAML para que sejam trocados os ENTERs por espaços (quem vai fazer isso é o parser), nesse caso utilizamos o operador '>'

myString: >
  "Post de YAML
  exemplo de string.

  Novo paragrafo"

Em python a configuração acima se traduz em:   

{'myString': '"Post de YAML exemplo de string. Novo paragrafo"\n'}

Listas

Para definir uma lista se utiliza o carater '-' por cada item da lista.

roteadores:
  - R1
  - R2
  - R3

A estrutura de dados acima pode ser lida como: "A chave 'roteadores' tem como valor a lista de valores R1,R2 e R3'.

Em python ficaria:

{'roteadores': ['R1', 'R2', 'R3']}
Inclusive posso ter valores duplicados na lista, isso não é um problema.

roteadores:
  - router
  - router

A estrutura acima pode ser lida como: "A chave 'roteadores' tem como valor uma lista, que a sua vez contem dois itens; item-0=router e item-1=router"

Em python ficaria:

{'roteadores': ['router', 'router']}

Diccionarios

Dicionarios são estruturas de dados com um conjunto de mapeamentos do tipo chave:valor

R1:
  hostname: 'R1SP'
  ip: '1.1.1.1'
  user: 'cisco'
  pass: 'cisco'

A estrutura de dados acima pode ser lida como: "A chave 'R1', tem como valor um outro conjunto de pares chave:valor hostname:'R1SP', ip:'1.1.1.1' etc.

Em Python ficaria:

{'R1': 

   {'hostname': 'R1SP', 
    'ip': '1.1.1.1', 
    'pass': 'cisco', 
    'user': 'cisco'}
}

No caso de diccionarios não é possivél ter chaves duplicadas. Exemplo:

R1:
  hostname: 'R1SP'
  ip: '1.1.1.1'
  user: 'cisco'
  pass: 'cisco'
  ip: '11.11.11.11'

No exemplo acima o valor para a chave 'ip' será '11.11.11.11'. Ao colocar a mesma chave, o valor para essa chave será sobreescrito.

Em python ficaria:

{'R1': 
   {'hostname': 'R1SP', 
    'ip': '11.11.11.11', 
    'pass': 'cisco', 
    'user': 'cisco'}
}


Existe a possibilidade de combinar diccionarios e listas.

Exemplo, preciso definir uma configuração para dois roteadores e tenho os seguintes dados:

Roteador1: Nome R1SP, ip de acesso 1.1.1.1

Roteador2: Nome R2SP ip de acesso 2.2.2.2

A configuração YAML poderia ficar:

roteadores:
 - router:
     hostname: 'R1SP'
     ip: '1.1.1.1'
 - router:
     hostname: 'R2SP'
     ip: '2.2.2.2'


Em Python ficaria:


{'roteadores': 
   [{'router': {'hostname': 'R1SP', 'ip': '1.1.1.1'}}, 
    {'router': {'hostname': 'R2SP', 'ip': '2.2.2.2'}}
   ]
}

Vamos asignar o valor do diccionario acima para a variável MyRouters em python, e ir acessando aos valores da estrutura na medida que nos aprondufamos na hierarquia.

>>> import yaml

>>> MyRouters={'roteadores': 
...    [{'router': {'hostname': 'R1SP', 'ip': '1.1.1.1'}}, 
...     {'router': {'hostname': 'R2SP', 'ip': '2.2.2.2'}}
...    ]
... }
>>> MyRouters['roteadores']
[{'router': {'ip': '1.1.1.1', 'hostname': 'R1SP'}}, {'router': {'ip': '2.2.2.2', 'hostname': 'R2SP'}}]

>>> MyRouters['roteadores'][0]
{'router': {'ip': '1.1.1.1', 'hostname': 'R1SP'}}

>>> MyRouters['roteadores'][1]
{'router': {'ip': '2.2.2.2', 'hostname': 'R2SP'}}

>>> MyRouters['roteadores'][0]['router']
{'ip': '1.1.1.1', 'hostname': 'R1SP'}

>>> MyRouters['roteadores'][1]['router']
{'ip': '2.2.2.2', 'hostname': 'R2SP'}

>>> MyRouters['roteadores'][0]['router']['ip']
'1.1.1.1'

>>> MyRouters['roteadores'][1]['router']['ip']
'2.2.2.2'
>>> 


Existe um site de parseamento online, onde vocês podem praticar http://yaml-online-parser.appspot.com/. No site vocês colocam sua configuração YAML e escolhem como saída Python. Ele vai lhes mostrar qual será a estrutura em python do seu arquivo YAML.

Um outro exemplo, um switch para o qual precisa ser gerado uma configuração para 3 VLANs, e OSPF.


SW1:
 router-id: "1.1.1.1"
 vlans:
    - vlan: 
       id: 100
       desc: "Vlan da rede 192.168.100.0"
    - vlan: 
       id: 200
       desc: "Vlan da rede 192.168.200.0"
    - vlan: 
       id: 300
       desc: "Vlan da rede 10.10.10.0"
    
 ospf:
    networks:
     - network:
        net: 192.168.100.0 
        netmask: "255.255.255.0"
        area: 0
     - network:
        net: 192.168.200.0 
        netmask: "255.255.255.128"
        area: 1
     - network:
        net: 10.10.10.0 
        netmask: "255.255.255.0"
        area: 2


Por hoje é isso Pessoal!!... Um Feliz Dia das Mais!!

Abçs
Jose

Nenhum comentário:

LinkWithin

Related Posts with Thumbnails