Desejo implantar alguns procedimentos armazenados em várias instâncias do MSSQL em vários servidores. No meu playbook eu tenho uma tarefa que reúne todas as instâncias em um servidor que eu uso nas seguintes tarefas para fazer um loop em qualquer instância. Eu uso esse método em muitos dos meus playbooks, mas neste também preciso ser capaz de usar uma variável reunida anteriormente em uma when
condição enquanto faço o loop da tarefa.
Estas são as partes relevantes do meu manual:
#################### GATHER INSTANCES ####################
- name: list instances
win_shell: (Find-DbaInstance -ComputerName localhost | Where Availability -eq 'Available').instancename
changed_when: False
register: sql_instances
#################### GATHER PROCEDURES ####################
- name: list procedures
win_shell: (Get-DbaDbStoredProcedure -SqlInstance localhost\{{ item }} -Database master -Schema dbo).Name
changed_when: False
register: sql_procedures
loop: "{{ sql_instances.stdout_lines }}"
#################### INSTALL CUSTOM PROCEDURES ####################
- name: my_procedure
ansible.windows.win_powershell:
script: |
$batch_install_prodecure = @'
--My Stored Procedure
'@
Invoke-DbaQuery -SqlInstance localhost\{{ item }} -Query $batch_install_prodecure
when: sql_procedures.stdout_lines.find('my_procedure') != 0
register: my_procedure
loop: "{{ sql_instances.stdout_lines }}"
Esta é a saída:
#################### GATHER INSTANCES ####################
"stdout_lines": [
"MSSQLSERVER2",
"MSSQLSERVER"
]
#################### GATHER PROCEDURES ####################
"stdout_lines": [
"sp_Something",
"sp_Somethingelse"
],
"stderr_lines": [],
"_ansible_no_log": false,
"item": "MSSQLSERVER2",
"ansible_loop_var": "item",
"_ansible_item_label": "MSSQLSERVER2"
}
############################
"stdout_lines": [
"sp_Something",
"sp_Somethingelse"
],
"stderr_lines": [],
"_ansible_no_log": false,
"item": "MSSQLSERVER",
"ansible_loop_var": "item",
"_ansible_item_label": "MSSQLSERVER"
}
#################### INSTALL CUSTOM PROCEDURES ####################
The conditional check 'sql_procedures.stdout_lines.find('custProc_Backupcheck') != 0' failed. The error was: error while evaluating conditional (sql_procedures.stdout_lines.find('custProc_Backupcheck') != 0): 'dict object' has no attribute 'stdout_lines'
Eu meio que entendo porque não funciona. Eu tenho que descrever de alguma forma com qual item a variável é encontrada, pois ela é gerada em um loop. Eu só não sei como fazer isso.
O mais longe que cheguei até agora é tentar implementar algo parecido como foi feito neste post , mas acho que esse método não se aplica ao meu caso
Eu sei que poderia facilmente fazer tudo isso diretamente no PowerShell, mas no final meu objetivo é instalar vários procedimentos (um por tarefa) e também poder remover facilmente os mais antigos para manter um inventário idêntico de procedimentos em minhas instâncias MSSQL.
Alguém pode me dizer como devo definir a when
condição para atingir meu objetivo?
Editar:
Veja a resposta aceita para saber por que não funciona.
Agora mudei para verificar, se o procedimento já está instalado ou não, no PowerShell:
#################### INSTALL CUSTOM PROCEDURES ####################
- name: my_procedure
ansible.windows.win_powershell:
script: |
$name_procedure = 'my_procedure'
$install_prodecure = @'
--My Stored Procedure
'@
if ((Get-DbaDbStoredProcedure -SqlInstance localhost\{{ item }} -Database master -Schema dbo).Name -contains $name_procedure) {
write-host "OK: SP $name_procedure is already installed"
} else {
write-host "SET: SP $name_procedure needs to be installed"
Invoke-DbaQuery -SqlInstance localhost\{{ item }} -Query $install_prodecure
if ((Get-DbaDbStoredProcedure -SqlInstance localhost\{{ item }} -Database master -Schema dbo).Name -contains $name_procedure) {
write-host "OK: SP $name_procedure sucessfully installed"
} else {
write-host "ERROR: Was not able to install $name_procedure"
}
}
register: my_procedure
loop: "{{ sql_instances.stdout_lines }}"
failed_when: my_procedure.host_out.find('ERROR:') != -1
changed_when: my_procedure.host_out.find('SET:') != -1
"Quando você usa registrar com um loop, a estrutura de dados colocada na variável conterá um atributo de resultados que é uma lista de todas as respostas do módulo."
https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html#registering-variables-with-a-loop
então para isso:
o
sql_procedures
será um array de dicts contendo os resultados em cada elemento desql_procedures.results[*].stdout_lines
Um loop mais complexo provavelmente ajudaria. Dê uma olhada no exemplo de iteração sobre listas aninhadas que é praticamente o que você deseja alcançar (os procedimentos são cada servidor)