Ky kjo artikull është krejtësisht praktik dhe i dedikohet historisë sime të trishtë
Duke u pĂ«rgatitur pĂ«r Zero Touch PROD pĂ«r RDS (MS SQL), pĂ«r tĂ« cilin na kanĂ« thĂ«nĂ« vazhdimisht, bĂ«ra njĂ« prezantim (POC â ProvĂ« e Konceptit) tĂ« automatizimit: njĂ« set skenarĂ«sh powershell. Pas prezantimit, kur u qetĂ«suan duarthithjet e zhurmshme, duke kaluar nĂ« brohoritje tĂ« pandĂ«rprera, mĂ« thanĂ« â gjithçka Ă«shtĂ« nĂ« rregull, por pĂ«r arsye ideologjike tĂ« gjithĂ« Jenkins slaves punojnĂ« nĂ«n Linux!
A është e mundur? Të marrësh një DBA të tillë të ngrohtë nga Windows dhe ta fusësh në ferrin e powershell nën Linux? A nuk është kjo e egër?

Duhet të zhytsha në këtë kombinim të çuditshëm teknologjish. Natyrisht, të gjitha 30+ skenarët e mi u ndalën së funksionuari. Për habinë time, për një ditë të vetme pune, arrita të gjithçka ta rregulloja. Po shkruaj në gjurmët e nxehura. Pra, cilat pengesa mund të gjeni gjatë transferimit të skenarëve powershell nga Windows në Linux?
sqlcmd vs Invoke-SqlCmd
Të kujtoj ndryshimin kryesor mes tyre. Utilitari i vjetër sqlcmd punon gjithashtu nën Linux, me funksionalitet praktikisht identik. Pyetja për ekzekutim jepet me -Q, skedari i hyrjes si -i, dhe kyçi -o. Megjithatë, emrat e skedarëve, natyrisht, janë të ndjeshëm ndaj rastit. Nëse po përdorni -i, atëherë në fund të skedarit shkruani:
GO
EXITNëse në fund nuk ka EXIT, sqlcmd do të kalojë në pritje të hyrjes, dhe nëse para EXIT nuk ka GO, atëherë komanda e fundit nuk do të funksionojë. Në skedarin e daljes shkruhen të gjitha daljet, selects, mesazhe, print etj.
Invoke-SqlCmd jep rezultatet në formën e DataSet, DataTables ose DataRows. Prandaj, nëse mund të përpunoni rezultatin e një select të thjeshtë nëpërmjet sqlcmd, duke shqyrtuar daljen e tij, është praktikisht e pamundur të nxirrni diçka të komplikuar: për këtë ka Invoke-SqlCmd. Por kjo komandë ka edhe hile të sajat:
- Nëse i jepni një skedar përmes -InputFile, nuk është e nevojshme, madje, ajo jep një gabim sintaksor EXIT -OutputFile
- jo, komanda ju kthen rezultatin në formën e një objekti Për të specifikuar serverin ka dy sintaksa:
- -ServerInstance -Username -Password -Database -ConnectionString dhe përmes . Siç duket, në rastin e parë nuk mund të specifikoni një port që është ndryshe nga 1433.dalja tekstuale, si PRINT, e cila kapet lehtësisht
- , për sqlcmdparaqet një problem Invoke-SqlCmd
- probabilisht në Linux tuaj ky cmdlet nuk ekziston!
u bë i disponueshëm për platformat që nuk janë Windows Zëvendësimi i variablave
Zëvendësimi i variablave
Në sqlcmd ka zëvendësime variable me anë të -v, për shembull, kështu:
# $conn ŃĐŸĐŽĐ”ŃĐ¶ĐžŃ ĐœĐ°ŃĐ°Đ»ĐŸ ĐșĐŸĐŒĐ°ĐœĐŽŃ sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res
-v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmdNë skriptin SQL ne përdorim zëvendësime:
set @spid=$(spid)
set @age=$(age)KĂ«shtu qĂ«. NĂ« *nix zĂ«vendĂ«simet e variablave nuk funksionojnĂ«. Parametri -v inxhorsohet. NĂ« Invoke-SqlCmd inxhorsohet -Variablat. Edhe pse parametri qĂ« pĂ«rcakton vetĂ« variablat inxhorsohet, zĂ«vendĂ«simet funksionojnĂ« â mund tĂ« pĂ«rdorni çdo variabĂ«l nga Shell. MegjithatĂ«, unĂ« u mĂ«rzita me variablat dhe vendosa qĂ« tĂ« mos varem nga to fare, dhe e bĂ«ra nĂ« mĂ«nyrĂ« primitive, e mira qĂ« skriptet SQL janĂ« tĂ« shkurtra:
# 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"Kjo, siç e kuptuat, është një test nga versioni Unix.
Ngarkimi i skedave
Në versionin Windows çdo operacion ishte i shoqëruar me auditimin: ekzekutuam sqlcmd, morëm ndonjë sharje në file-in e output-it, e bashkëngjitëm atë file në tavolinën e auditit. Më vjen mirë që SQL server punon në të njëjtin server me Jenkins, kjo bëhej më pak siç vijon:
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
returnKështu që ne e thithim file-in BCP plotësisht, dhe e futim në fushën nvarchar(max) të tavolinës së auditi. Natyrisht, e gjithë kjo sistem ra, pasi në vend të SQL server, morëm RDS, dhe BULK INSERT nuk punon fare për UNC për shkak të përpjekjes për të marrë një lok ekskluziv mbi file-in, dhe ndihmës me RDS është në fillim i destinuar për të dështuar. Prandaj, vendosa të ndryshoj dizajnin e sistemit, duke mbajtur auditin rresht pas rreshti:
CREATE TABLE AuditOut (
ID int NULL,
TextLine nvarchar(max) NULL,
n int IDENTITY(1,1) PRIMARY KEY
)Dhe të shkruaj në këtë tavolinë kështu:
function WriteAudit([string]$Filename, [string]$ConnStr,
[string]$Tabname, [string]$Jobname)
{
# merr $lastid e ekzekutimit të fundit -- e hequr për artikull
#krijo grid dhe e mbush atë me të dhëna nga skedari
$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)
}
# shkruaj në tabelë
$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()
}
Për të përzgjedhur përmbajtjen duhet bërë select sipas ID-së, duke përzgjedhur në rendin n (identiteti).
Në artikullin e ardhshëm, do të ndalem më thellësisht se si ndërveprojnë të gjitha këto me Jenkins.
Burimi: habr.com
