Nagtrabaho sa MS SQL gikan sa Powershell sa Linux

Kini nga artikulo pulos praktikal ug gipahinungod sa akong makapasubo nga istorya

Pag-andam alang sa Zero Touch PROD alang sa RDS (MS SQL), diin ang tanan namong mga dalunggan nagbagting, naghimo ako usa ka presentasyon (POC - Proof Of Concept) sa automation: usa ka set sa mga script sa powershell. Pagkahuman sa presentasyon, sa dihang ang mabagyo, dugay nga pagpamakpak nawala, nahimong walay hunong nga palakpak, gisultihan nila ako - kining tanan maayo, apan alang lamang sa mga hinungdan sa ideolohiya, ang tanan namong mga ulipon nga Jenkin nagtrabaho sa Linux!

Posible ba kini? Kuhaa ang ingon ka init, lampara nga DBA gikan sa ilawom sa Windows ug ibutang kini sa kainit sa powershell sa ilawom sa Linux? Dili ba kini mapintas?

Nagtrabaho sa MS SQL gikan sa Powershell sa Linux
Kinahanglan nakong isawsaw ang akong kaugalingon niining talagsaon nga kombinasyon sa mga teknolohiya. Siyempre, ang tanan nakong 30+ nga mga script mihunong sa pagtrabaho. Sa akong katingala, nakahimo ko sa pag-ayo sa tanan sa usa ka adlaw sa trabaho. Nagsulat ako sa mainit nga paggukod. Busa, unsa nga mga lit-ag ang imong masugatan sa pagbalhin sa mga script sa powershell gikan sa Windows ngadto sa Linux?

sqlcmd batok sa Invoke-SqlCmd

Tugoti ako nga pahinumdoman ka sa panguna nga kalainan tali kanila. Maayo nga daan nga gamit sqlcmd Naglihok usab kini ubos sa Linux, nga adunay halos parehas nga gamit. Gipasa namo ang pangutana aron ipatuman ang -Q, ang input file isip -i, ug ang output isip -o. Apan ang mga ngalan sa file, siyempre, gihimo nga sensitibo sa kaso. Kung mogamit ka -i, unya sa file isulat sa katapusan:

GO
EXIT

Kung walay EXIT sa katapusan, ang sqlcmd magpadayon sa paghulat alang sa input, ug kung kaniadto EXIT dili GO, unya ang kataposang sugo dili molihok. Ang output file naglangkob sa tanan nga mga output, gipili, mga mensahe, pag-imprinta, ug uban pa.

Ang Invoke-SqlCmd naghimo sa resulta isip DataSet, DataTables o DataRows. Busa, kung imong iproseso ang resulta sa usa ka yano nga pagpili, mahimo nimong gamiton sqlcmd, sa pag-parse sa output niini, halos imposible nga makuha ang usa ka butang nga komplikado: kay kini adunay Invoke-SqlCmd. Apan kini nga team usab adunay kaugalingon nga mga komedya:

  • Kung magbalhin ka ug file sa iya pinaagi sa -InputFile, dayon EXIT dili kinahanglan, dugang pa, nagpatungha kini usa ka sayup sa syntax
  • -OutputFile dili, ang sugo nagbalik kanimo sa resulta isip usa ka butang
  • Adunay duha ka mga syntax alang sa pagtino sa usa ka server: -ServerInstance -Username -Password -Database ug pinaagi -ConnectionString. Katingad-an, sa una nga kaso dili posible nga mahibal-an ang usa ka pantalan gawas sa 1433.
  • output sa teksto, type ang PRINT, nga yano nga "nasakpan" sqlcmdpara Invoke-SqlCmd usa ka problema
  • Ug labing importante: Lagmit ang imong Linux wala niini nga cmdlet!

Ug kini ang panguna nga problema. Sa Marso ra kini nga cmdlet nahimong magamit alang sa dili Windows nga mga plataporma, ug sa kataposan makapadayon na ta!

Variable nga pagpuli

Ang sqlcmd adunay variable substitution gamit ang -v, pananglitan sama niini:

# $conn содСрТит Π½Π°Ρ‡Π°Π»ΠΎ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res 
  -v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmd

Sa script sa SQL gigamit namon ang mga substitusyon:

set @spid=$(spid)
set @age=$(age)

Busa ania kini. Sa *nix Ang mga variable substitution dili molihok. Parameter -v gibalewala. U Invoke-SqlCmd gibalewala -Mga variable. Bisan kung ang parameter nga nagtino sa mga variable sa ilang kaugalingon wala gibalewala, ang mga substitusyon mismo nagtrabaho-mahimo nimong magamit ang bisan unsang mga variable gikan sa Shell. Bisan pa, nasakitan ako sa mga variable ug nakahukom nga dili magsalig sa kanila, ug naglihok nga dili maayo ug karaan, tungod kay ang mga script sa SQL mubo:

# prepend the parameters  
"declare @age int, @spid int" | Add-Content "q.sql"
"set @spid=" + $spid | Add-Content "q.sql"
"set @age=" + $age | Add-Content "q.sql"

foreach ($line in Get-Content "Sqlserver/Automation/KillSpid.sql") { 
  $line | Add-Content "q.sql" 
  }
$cmd = "/opt/mssql-tools/bin/" + $conn + " -i q.sql -o res.log"

Kini, sumala sa imong nasabtan, usa ka pagsulay gikan na sa bersyon sa Unix.

Pag-upload sa mga file

Sa bersyon sa Windows, ang bisan unsang operasyon giubanan sa usa ka pag-audit: nagpadagan kami sa sqlcmd, nakadawat usa ka matang sa pag-abuso sa output file, gilakip kini nga file sa plato sa pag-audit. Maayo na lang, ang SQL server nagtrabaho sa parehas nga server sama sa Jenkins, nahimo kini nga sama niini:

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

Sa ingon, atong gilamoy ang BCP file sa hingpit ug iduso kini ngadto sa nvarchar(max) field sa audit table. Siyempre, kini nga tibuuk nga sistema nahulog, tungod kay imbes nga usa ka SQL server nakuha nako ang RDS, ug ang BULK INSERT wala gyud molihok pinaagi sa UNC tungod sa pagsulay sa pagkuha sa usa ka eksklusibo nga kandado sa usa ka file, ug uban ang RDS kini sa kasagaran gitakda gikan sa. sa sinugdanan pa lang. Mao nga nakahukom ko nga usbon ang disenyo sa sistema, gitipigan ang linya sa pag-audit sa linya:

CREATE TABLE AuditOut (
  ID int NULL,
  TextLine nvarchar(max) NULL,
  n int IDENTITY(1,1) PRIMARY KEY
  )

Ug isulat niini nga lamesa sama niini:

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() 
  }  

Aron makapili sa sulod, kinahanglan ka nga mopili pinaagi sa ID, pagpili sa han-ay n (identity).

Sa sunod nga artikulo moadto ako sa dugang nga detalye kung giunsa kini tanan nakig-uban sa Jenkins.

Source: www.habr.com

Idugang sa usa ka comment