Este artículo es puramente práctico y está dedicado a mi triste historia.
Preparándome para
Zero Touch PROD para RDS (MS SQL), sobre el cual todos nuestros oídos estaban zumbando, hice una presentación (POC - Proof Of Concept) de automatización: un conjunto de scripts de PowerShell. Después de la presentación, cuando el fuerte y prolongado aplauso se calmó, convirtiéndose en una ovación incesante, me dijeron que todo esto es bueno, ¡pero solo por razones ideológicas todos tenemos esclavos de Jenkins corriendo bajo Linux!
¿Es eso posible? ¿Para tomar un DBA de tubo tan cálido debajo de Windows y ponerlo al calor de PowerShell en Linux? ¿No es eso cruel?
Tuve que sumergirme en esta extraña combinación de tecnología. Por supuesto, todos mis más de 30 scripts dejaron de funcionar. Para mi sorpresa, en un día hábil logré arreglar todo. Estoy escribiendo en persecución. Entonces, ¿qué dificultades puede encontrar al portar scripts de PowerShell de Windows a Linux?
sqlcmd vs Invoke-SqlCmd
Déjame recordarte la diferencia principal entre ellos. La buena y antigua utilidad
sqlcmd también funciona en Linux, con una funcionalidad casi idéntica. Pasamos la consulta a -Q, el archivo de entrada como -i y la salida -o. Estos son solo los nombres de archivo, por supuesto, distinguen entre mayúsculas y minúsculas. Si usa -i, escriba el archivo al final:
GO EXIT
Si no hay EXIT al final, entonces sqlcmd irá a esperar la entrada, y si no hay
GO antes de
EXIT , el último comando no funcionará. Todos los resultados, selecciones, mensajes, impresiones, etc., llegan al archivo de salida.
Invoke-SqlCmd devuelve el resultado como un DataSet, DataTables o DataRows. Por lo tanto, si puede procesar el resultado de una simple selección a través de
sqlcmd ,
analizando su salida, entonces generar algo complicado es casi imposible: hay
Invoke-SqlCmd para esto. Pero este equipo tiene sus propios chistes:
- Si le pasa el archivo a través de -InputFile , entonces EXIT no es necesario, además, da un error de sintaxis
- -OutputFile not, el comando le devuelve el resultado como un objeto
- Hay dos sintaxis para especificar un servidor: -ServerInstance -Username -Password -Database y mediante -ConnectionString . Curiosamente, en el primer caso, no puede especificar un puerto que no sea 1433.
- la salida de texto, de tipo PRINT, que es "capturada" por sqlcmd de manera elemental, es un problema para Invoke-SqlCmd
- Y lo más importante: lo más probable es que este cmdlet no esté en su Linux.
Y este es el principal problema. ¡Solo en marzo este cmdlet
estuvo disponible para plataformas que no son de Windows , y finalmente podemos avanzar!
Sustitución variable
Sqlcmd tiene una sustitución variable con -v, así:
En el script SQL, usamos sustituciones:
set @spid=$(spid) set @age=$(age)
Entonces aquí. En * nix
, las sustituciones variables no funcionan . La
opción -v se ignora.
Invoke-SqlCmd ignora
-Variables . Aunque se ignora el parámetro que establece las variables en sí, las sustituciones en sí funcionan: puede usar cualquier variable de Shell. Sin embargo, las variables me ofendieron y decidí no depender de ellas en absoluto, y actué de manera aproximada y primitiva, ya que los scripts para sql son cortos:
Esto, como entiendes, es una prueba de la versión Unix.
Subir archivos
En la versión de Windows, cualquier operación que tuve fue acompañada por una auditoría: realizaron sqlcmd, obtuvieron algún tipo de abuso en el archivo de salida, adjuntaron este archivo a la placa de auditoría. Afortunadamente, el servidor SQL funcionó en el mismo servidor que Jenkins, se hizo algo como esto:
CREATE procedure AuditUpload @id int, @filename varchar(256) as set nocount on declare @sql varchar(max) CREATE TABLE
Por lo tanto, nos tragamos todo el archivo BCP y colocamos la tabla de auditoría en el campo nvarchar (max). Por supuesto, todo este sistema se derrumbó, porque en lugar del servidor SQL obtuve RDS, y BULK INSERT no funciona en \\ UNC debido a un intento de llevar un bloqueo exclusivo a un archivo, y con RDS esto está inicialmente condenado. Entonces decidí cambiar el diseño del sistema, almacenando la auditoría línea por línea:
CREATE TABLE AuditOut ( ID int NULL, TextLine nvarchar(max) NULL, n int IDENTITY(1,1) PRIMARY KEY )
Y escriba a esta tabla así:
function WriteAudit([string]$Filename, [string]$ConnStr, [string]$Tabname, [string]$Jobname) {
Para seleccionar contenido, seleccione por ID, eligiendo n (identidad) en orden.
En el próximo artículo me detendré en más detalles sobre cómo todo esto interactúa con Jenkins.