Hierdie artikel is bloot prakties en word opgedra aan my hartseer verhaal
Maak gereed vir Zero Touch PROD vir RDS (MS SQL), waaroor ons almal se ore gegons het, het ek 'n aanbieding (POC - Proof Of Concept) van outomatisering gemaak: 'n stel powershell-skrifte. Na die aanbieding, toe die stormagtige, langdurige applous bedaar en in onophoudelike applous verander het, het hulle vir my gesê - dit alles is goed, maar net om ideologiese redes werk al ons Jenkins-slawe op Linux!
Is dit moontlik? Neem so 'n warm, lamp DBA van onder Windows en plak dit in die hitte van powershell onder Linux? Is dit nie wreed nie?
Ek moes myself in hierdie vreemde kombinasie van tegnologieë verdiep. Natuurlik het al my 30+ skrifte opgehou werk. Tot my verbasing het ek daarin geslaag om alles in een werksdag reg te maak. Ek skryf op heterdaad. So, watter slaggate kan jy teëkom wanneer jy powershell-skrifte van Windows na Linux oordra?
sqlcmd vs Invoke-SqlCmd
Laat ek jou herinner aan die belangrikste verskil tussen hulle. Goeie ou nut sqlcmd Dit werk ook onder Linux, met byna identiese funksionaliteit. Ons gee die navraag deur om -Q uit te voer, die invoerlêer as -i, en die uitvoer as -o. Maar die lêername word natuurlik hooflettergevoelig gemaak. As jy -i gebruik, skryf dan in die lêer aan die einde:
GO
EXIT
As daar geen UITGANG aan die einde is nie, sal sqlcmd voortgaan om te wag vir invoer, en as voor EXIT sal nie GO, dan sal die laaste opdrag nie werk nie. Die uitvoerlêer bevat al die afvoer, keuses, boodskappe, druk, ens.
Invoke-SqlCmd produseer die resultaat as 'n DataSet, DataTables of DataRows. Daarom, as jy die resultaat van 'n eenvoudige seleksie verwerk, kan jy dit gebruik sqlcmd, nadat die uitset daarvan ontleed is, is dit byna onmoontlik om iets kompleks af te lei: hiervoor is daar Roep-SqlCmd. Maar hierdie span het ook sy eie grappies:
As jy 'n lêer na haar oordra via - Invoerlêer, Dan EXIT nie nodig nie, bowendien produseer dit 'n sintaksfout
-Uitvoerlêer nee, die opdrag gee vir jou die resultaat as 'n voorwerp terug
Daar is twee sintakse om 'n bediener te spesifiseer: -ServerInstance -Gebruikernaam -Wagwoord -Databasis en deur -ConnectionString. Vreemd genoeg is dit in die eerste geval nie moontlik om 'n ander poort as 1433 te spesifiseer nie.
teksuitvoer, tik PRINT, wat eenvoudig "gevang" word sqlcmdvir Roep-SqlCmdis 'n probleem
sqlcmd het veranderlike vervanging deur -v te gebruik, byvoorbeeld soos volg:
# $conn содержит начало команды sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res
-v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmd
In die SQL script gebruik ons vervangings:
set @spid=$(spid)
set @age=$(age)
So hier is dit. In *nix veranderlike vervangings werk nie... Parameter -v geïgnoreer. U Roep-SqlCmd geïgnoreer -Veranderlikes. Alhoewel die parameter wat die veranderlikes self spesifiseer geïgnoreer word, werk die vervangings self - jy kan enige veranderlikes van Shell gebruik. Ek was egter beledig deur die veranderlikes en het besluit om glad nie daarvan afhanklik te wees nie, en het onbeskof en primitief opgetree, aangesien die SQL-skrifte kort is:
Dit, soos u verstaan, is 'n toets wat reeds van die Unix-weergawe af is.
Laai lêers op
In die Windows-weergawe is enige bewerking vergesel van 'n oudit: ons het sqlcmd gehardloop, 'n soort misbruik in die uitvoerlêer ontvang, hierdie lêer aan die ouditplaat geheg. Gelukkig het SQL-bediener op dieselfde bediener as Jenkins gewerk, dit is so iets gedoen:
CREATE procedure AuditUpload
@id int, @filename varchar(256)
as
set nocount on
declare @sql varchar(max)
CREATE TABLE #multi (filer NVARCHAR(MAX))
set @sql='BULK INSERT #multi FROM '''+@filename
+''' WITH (ROWTERMINATOR = '' '',CODEPAGE = ''ACP'')'
exec (@sql)
select @sql=filer from #multi
update JenkinsAudit set multiliner=@sql where ID=@id
return
Dus, ons sluk die BCP-lêer heeltemal in en skuif dit in die nvarchar(max)-veld van die oudittabel. Natuurlik het hierdie hele stelsel uitmekaar geval, want in plaas van 'n SQL-bediener het ek RDS gekry, en BULK INSERT werk glad nie via UNC nie as gevolg van 'n poging om 'n eksklusiewe slot op 'n lêer te neem, en met RDS is dit oor die algemeen gedoem van die heel begin. Ek het dus besluit om die stelselontwerp te verander en die oudit reël vir reël te stoor:
CREATE TABLE AuditOut (
ID int NULL,
TextLine nvarchar(max) NULL,
n int IDENTITY(1,1) PRIMARY KEY
)
En skryf so in hierdie tabel:
function WriteAudit([string]$Filename, [string]$ConnStr,
[string]$Tabname, [string]$Jobname)
{
# get $lastid of the last execution -- проскипано для статьи
#create grid and populate it with data from file
$audit = Get-Content $Filename
$DT = new-object Data.DataTable
$COL1 = new-object Data.DataColumn;
$COL1.ColumnName = "ID";
$COL1.DataType = [System.Type]::GetType("System.Int32")
$COL2 = new-object Data.DataColumn;
$COL2.ColumnName = "TextLine";
$COL2.DataType = [System.Type]::GetType("System.String")
$DT.Columns.Add($COL1)
$DT.Columns.Add($COL2)
foreach ($line in $audit)
{
$DR = $dt.NewRow()
$DR.Item("ID") = $lastid
$DR.Item("TextLine") = $line
$DT.Rows.Add($DR)
}
# write it to table
$conn=new-object System.Data.SqlClient.SQLConnection
$conn.ConnectionString = $ConnStr
$conn.Open()
$bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $ConnStr
$bulkCopy.DestinationTableName = $Tabname
$bulkCopy.BatchSize = 50000
$bulkCopy.BulkCopyTimeout = 0
$bulkCopy.WriteToServer($DT)
$conn.Close()
}
Om inhoud te kies, moet jy volgens ID kies, kies in volgorde n (identiteit).
In die volgende artikel gaan ek in meer besonderhede in oor hoe dit alles met Jenkins in wisselwerking tree.