Introdução
TextFSM é um módulo Python que utiliza um motor de máquina de estados finitos (FSM) com base em templates para analisar texto semiestruturado. Originalmente concebido para extrair dados de saídas de linhas de comando (CLI) de dispositivos de rede, como roteadores e switches, sua aplicação pode ser estendida a qualquer tipo de saída textual que siga um padrão. O sistema requer dois elementos principais: um arquivo de template e os dados textuais de entrada (por exemplo, a saída de um comando CLI). Como resultado, ele retorna uma estrutura tabular contendo os dados extraídos.
É importante notar que cada estrutura de texto distinta requer seu próprio arquivo de template. A comunidade é encorajada a desenvolver e compartilhar templates para diversas fontes de dados. A criação de um repositório de templates permite que scripts chamem o TextFSM para extrair informações úteis de várias fontes, possibilitando também a geração de diferentes visualizações tabulares a partir dos mesmos dados, utilizando templates distintos.
Funcionamento Detalhado
Utilizando a Biblioteca
Um exemplo rápido de como usar a biblioteca:
import textfsm
# Carrega o template e os dados brutos
with open("meu_template.textfsm", "r") as template_file:
raw_cli_output = "..." # Sua string de saída CLI aqui
# Cria a instância do TextFSM
fsm_parser = textfsm.TextFSM(template_file)
# Analisa o texto
parsed_data = fsm_parser.ParseText(raw_cli_output)
# Exibe os resultados em formato CSV
print( ', '.join(fsm_parser.header) )
for row in parsed_data:
print( ', '.join(row) )
A biblioteca também pode ser executada diretamente pela linha de comando para validar a sintaxe do template e comparar a saída esperada com a entrada:
python -m textfsm.parser [--help] <template_file> [input_file] [output_file]
</template_file>
Se o TextFSM for instalado como um pacote, o executável parser.py estará localizado no diretório de pacotes do Python correspondente à sua versão.
Estrutura dos Dados Extraídos
O objetivo principle do FSM é extrair dados cruciais de entradas de texto e organizá-los em um formato tabular. Considere a seguinte entrada de dados brutos, onde o interesse reside no estado e na temperatura das unidades de processamento:
Routing Engine status:
Slot 0:
Current state Master
Election priority Master (default)
Temperature 39 degrees C / 102 degrees F
CPU temperature 55 degrees C / 131 degrees F
DRAM 2048 MB
Memory utilization 76 percent
CPU utilization:
User 95 percent
Background 0 percent
Kernel 4 percent
Interrupt 1 percent
Idle 0 percent
Model RE-4.0
Serial ID xxxxxxxxxxxx
Start time 2008-04-10 20:32:25 PDT
Uptime 180 days, 22 hours, 45 minutes, 20 seconds
Load averages: 1 minute 5 minute 15 minute
0.96 1.03 1.03
Routing Engine status:
Slot 1:
Current state Backup
Election priority Backup
Temperature 30 degrees C / 86 degrees F
CPU temperature 31 degrees C / 87 degrees F
DRAM 2048 MB
Memory utilization 14 percent
CPU utilization:
User 0 percent
Background 0 percent
Kernel 0 percent
Interrupt 1 percent
Idle 99 percent
Model RE-4.0
Serial ID xxxxxxxxxxxx
Start time 2008-01-22 07:32:10 PST
Uptime 260 days, 10 hours, 45 minutes, 39 seconds
Aplicando um template apropriado ao TextFSM para processar essa entrada, o resultado é uma tabela onde os slots e seus dados associados são organizados em campos:
| Slot | Modelo | DRAM | Estado | Temperatura | TempCPU |
|---|---|---|---|---|---|
| 0 | RE-4.0 | 2048 | Master | 39 | 55 |
| 1 | RE-4.0 | 2048 | Backup | 30 | 31 |
Arquivos de Template
Um arquivo de template define como o FSM deve procesasr os dados de entrada. Diferentes formatos de texto exigem templates específicos; por exemplo, a saída de comandos de roteador geralmente necessita de um template dedicado para cada comando.
Abaixo está um exemplo completo de template, demonstrando como processar a saída do comando 'show chassis routing-engine' em um roteador:
# Template para 'show chassis routing-engine'
Value Filldown Chassis (.cc.?-re.)
Value Required Slot (\d+)
Value State (\w+)
Value Temp (\d+)
Value CPUTemp (\d+)
Value DRAM (\d+)
Value Model (\S+)
Start
^${Chassis}
^Routing Engine status: -> Record RESlot
RESlot
^\s+Slot\s+${Slot}
^\s+Current state\s+${State}
^\s+Temperature\s+${Temp} degrees
^\s+CPU temperature\s+${CPUTemp} degrees
^\s+DRAM\s+${DRAM} MB
^\s+Model\s+${Model} -> Start
Um arquivo de template é composto por duas seções principais:
- Definições de Valor (Value): Descrevem as colunas de dados a serem extraídas, que aparecerão na tabela resultante. Todas as definições de
Valuedevem preceder as definições de estado e ser adjacentes (exceto quando separadas por comentários). - Definições de Estado (State): Uma ou mais seções que descrevem os diferentes estados da máquina de estados durante o processo de análise.
Linhas que começam com um caractere '#' (possivelmente precedido por espaços em branco) são consideradas comentários.
Definições de Valor (Value)
Cada linha de definição de Value segue o formato:
Value [opção[,opção...]] nome regex
| Palavra-chave | Tipo | Descrição |
|---|---|---|
Value |
Obrigatório | Inicia a definição de um valor. |
opção |
Flags (separadas por vírgula, sem espaços) | - Filldown: Mantém o valor anterior para registros subsequentes, a menos que seja explicitamente alterado ou correspondido novamente. - Key: Declara que o conteúdo deste campo é um identificador único para a linha. - Required: A linha só será salva na tabela se este valor corresponder. - List: Indica que o valor é uma lista, acumulando correspondências em vez de sobrescrever. - Fillup: Similar a Filldown, mas preenche para cima até encontrar um registro não vazio. Incompatível com Required ou List. |
nome |
Nome do campo | Nome usado para o valor, que se tornará o nome da coluna na tabela final. Não pode conflitar com nomes de opções. |
regex |
Expressão regular | Uma expressão regular entre parênteses, usada para capturar o valor. |
Definições de Estado
Após as definições de Value, seguem as definições de estado. Cada definição de estado é separada por uma linha em branco. A primeira linha é o nome do estado (alfanumérico), seguida por uma série de regras.
O formato de uma definição de estado completa é:
NomeDoEstado
^regra1
^regra2
...
As regras dentro de um estado devem ser contíguas (sem linhas em branco) e precedidas por um ou dois espaços seguidos pelo caractere '^'.
O FSM inicia no estado Start. Uma linha de entrada só é comparada com as regras do estado atual. Uma correspondência pode acionar uma transição para um novo estado. O processamento linha a linha continua até que o estado EOF seja alcançado ou uma transição para o estado End ocorra.
Estados Reservados
O estado Start é obrigatório para iniciar o processamento. O estado EOF (End Of File) é um estado implícito que é executado quando o final da entrada é atingido. Ele normalmente executa um comando Record antes de retornar.
É possível sobrescrever o comportamento padrão do EOF definindo-o explicitamente:
EOF
^.* -> Record
Ou, para evitar qualquer ação:
EOF
O estado End é um estado reservado que encerra o processamento da entrada sem executar o estado EOF.
Regras de Estado
Cada definição de estado consiste em uma ou mais regras. O FSM lê uma linha da entrada e a compara sequencialmente com as regras do estado atual. Se uma regra corresponder, sua ação associada é executada, e o processo recomeça (geralmente a partir do estado Start ou do estado para o qual a transição foi definida).
O formato de uma regra é:
^regex [-> ação]
regex é uma expressão regular que deve corresponder ao início da linha de entrada. O caractere '^' é implicitamente adicionado.
A expressão regular pode conter descritores de valor no formato $ValorNome ou ${ValorNome} (preferencial). Ao encontrar uma correspondência, o texto capturado pelo regex associado ao valor é atribuído ao registro.
O final de uma linha pode ser marcado com $$, que será substituído por '$' durante a substituição do valor.
Exemplo:
Value Interface (\S+)
Start
^Interface ${Interface} is up
A regra acima se expandirá para:
^Interface (\S+) is up
Se a linha de entrada for "Interface GigabitEthernet1/10 is up.", o valor "GigabitEthernet1/10" será atribuído à variável Interface.
Múltiplos descritores de valor podem ser usados em uma única regra, exigindo que todas as correspondências adicionais sejam bem-sucedidas para que todos os valores sejam atribuídos.
Ações de Regra
Após a expressão regular, uma ação pode ser especificada, separada por ->. As ações são compostas por três partes opcionais: A) Ação de Linha, B) Ação de Registro, e C) Transição de Estado.
Se nenhuma ação for especificada (sem ->), a ação implícita padrão é Next.NoRecord.
Ações de Linha
| Ação | Descrição |
|---|---|
Next |
Processa a próxima linha de entrada, reiniciando a correspondência do estado atual. É a ação padrão se nenhuma ação de linha for especificada. |
Continue |
Mantém a linha atual e continua o processamento das regras no estado atual, como se a correspondência não tivesse ocorrido (a atribuição de valores ainda acontece). Comportamento de Continue não aceita transição de estado. |
Ações de Registro
Ocorrem após a ação de linha, separadas por um ponto (.).
| Ação | Descrição |
|---|---|
NoRecord |
Nenhuma ação de registro. É o padrão se nenhuma ação de registro for especificada. |
Record |
Adiciona os valores coletados até o momento como uma nova linha na tabela de resultados. Valores não Filldown são limpos. Se algum valor Required não foi atribuído, a linha não será adicionada. |
Clear |
Limpa os valores que não são Filldown. |
Clearall |
Limpa todos os valores. |
O ponto (.) é necessário apenas quando tanto a ação de linha quanto a de registro são explicitamente especificadas. Se uma ou ambas forem padrão, o ponto pode ser omitido.
Transição de Estado
Opcionalmente, um novo nome de estado pode ser especificado após as ações de linha ou registro, separado por um espaço. Isso indica uma transição para o novo estado. O novo estado deve ser válido e definido no template.
Após a execução das ações, uma nova linha é lida da entrada, o estado atual é alterado para o novo estado, e o processamento continua a partir daí.
Ação de Erro
A ação especial Error encerra todo o processamento, descarta os dados coletados até o momento e lança uma exceção. Pode incluir uma mensagem opcional.
^regex -> Error [palavra|"string"]