Este artigo é puramente prático e é dedicado à minha triste história.
Preparando-me para o
Zero Touch PROD para RDS (MS SQL), sobre o qual todos os nossos ouvidos estavam zumbindo, fiz uma apresentação (POC - Proof Of Concept) de automação: um conjunto de scripts do PowerShell. Após a apresentação, quando os aplausos altos e prolongados cessaram, transformando-se em uma ovação incessante, me disseram que tudo isso é bom, mas apenas por razões ideológicas, todos nós temos escravos Jenkins rodando no Linux!
Isso é possível? Tirar um DBA de tubo tão quente do Windows e colocá-lo no calor do PowerShell no Linux? Isso não é cruel?
Eu tive que mergulhar nessa estranha combinação de tecnologia. Obviamente, todos os meus mais de 30 scripts pararam de funcionar. Para minha surpresa, em um dia útil consegui consertar tudo. Estou escrevendo em perseguição. Então, que armadilhas você pode encontrar ao transportar scripts do PowerShell do Windows para o Linux?
sqlcmd vs Invoke-SqlCmd
Deixe-me lembrá-lo da principal diferença entre eles. O bom e velho utilitário
sqlcmd também funciona no Linux, com funcionalidade quase idêntica. Para executar a consulta, passamos -Q, o arquivo de entrada como -i e a saída -o. Aqui estão apenas os nomes dos arquivos, é claro, diferenciam maiúsculas de minúsculas. Se você usar -i, escreva no arquivo no final:
GO EXIT
Se não houver EXIT no final, o sqlcmd aguardará a entrada e, se não houver
GO antes de
EXIT , o último comando não funcionará. Toda saída, seleção, mensagem, impressão, etc., chega ao arquivo de saída.
Invoke-SqlCmd retorna o resultado como um DataSet, DataTables ou DataRows. Portanto, se você puder processar o resultado de uma seleção simples por meio do
sqlcmd ,
analisando sua saída, produzir algo complicado é quase impossível: existe
Invoke-SqlCmd para isso. Mas essa equipe tem suas próprias piadas:
- Se você passar o arquivo para ele via -InputFile , EXIT não é necessário, além disso, isso gera um erro de sintaxe
- -OutputFile não, o comando retorna o resultado como um objeto
- Existem duas sintaxes para especificar um servidor: -ServerInstance -Username -Password -Database e através de -ConnectionString . Curiosamente, no primeiro caso, você não pode especificar uma porta diferente de 1433.
- A saída de texto, do tipo PRINT, que é "capturada" pelo sqlcmd de maneira elementar, é um problema do Invoke-SqlCmd
- E o mais importante: provavelmente esse cmdlet não está no seu Linux!
E este é o principal problema. Somente em março, esse cmdlet
ficou disponível para plataformas não Windows e, finalmente, podemos seguir em frente!
Substituição variável
Sqlcmd tem substituição variável com -v, assim:
No script SQL, usamos substituições:
set @spid=$(spid) set @age=$(age)
Então aqui. No * nix
, as substituições de variáveis não funcionam . A
opção -v é ignorada.
Invoke-SqlCmd ignora
-Variables . Embora o parâmetro que define as variáveis em si seja ignorado, as próprias substituições funcionam - você pode usar quaisquer variáveis do Shell. No entanto, fiquei ofendido com as variáveis e decidi não depender delas, e agi de maneira grosseira e primitiva, pois os scripts para sql são curtos:
Este, como você entende, é um teste da versão Unix.
Carregar arquivos
Na versão do Windows, qualquer operação que eu realizava era acompanhada de uma auditoria: eles executavam o sqlcmd, obtinha algum tipo de abuso no arquivo de saída, anexava esse arquivo à placa de auditoria. Felizmente, o servidor SQL trabalhava no mesmo servidor que o Jenkins, era feito algo como isto:
CREATE procedure AuditUpload @id int, @filename varchar(256) as set nocount on declare @sql varchar(max) CREATE TABLE
Assim, engolimos o arquivo BCP inteiro e colocamos a tabela de auditoria no campo nvarchar (max). Obviamente, todo esse sistema desmoronou, porque, em vez do SQL Server, eu obtive o RDS, e o BULK INSERT não funciona no \\ UNC por tentar bloquear um arquivo exclusivamente, e com o RDS isso geralmente está condenado desde o início. Então, decidi mudar o design do sistema, armazenando a linha de auditoria por linha:
CREATE TABLE AuditOut ( ID int NULL, TextLine nvarchar(max) NULL, n int IDENTITY(1,1) PRIMARY KEY )
E escreva nesta tabela assim:
function WriteAudit([string]$Filename, [string]$ConnStr, [string]$Tabname, [string]$Jobname) {
Para selecionar o conteúdo, selecione por ID, escolhendo n (identidade) em ordem.
No próximo artigo, abordarei mais detalhadamente como tudo isso interage com Jenkins.