Ky artikull është thjesht praktik dhe i kushtohet historisë sime të trishtuar
Duke u përgatitur për Zero Touch PROD për RDS (MS SQL), për të cilin na gumëzhinin të gjithë veshët, bëra një prezantim (POC - Proof Of Concept) i automatizimit: një grup skriptesh powershell. Pas prezantimit, kur duartrokitjet e stuhishme, të zgjatura u shuan, duke u shndërruar në duartrokitje të pandërprera, ata më thanë - e gjithë kjo është e mirë, por vetëm për arsye ideologjike, të gjithë skllevërit tanë Jenkins punojnë në Linux!
A është e mundur kjo? Merrni një DBA kaq të ngrohtë dhe llambë nga Windows dhe ngjiteni në nxehtësinë e powershell nën Linux? A nuk është kjo mizore?
Më duhej të zhytesha në këtë kombinim të çuditshëm teknologjish. Sigurisht, të gjitha 30+ skenarët e mi nuk funksionuan. Për habinë time, arrita të rregulloja gjithçka brenda një dite pune. Unë jam duke shkruar në ndjekje të nxehtë. Pra, çfarë grackash mund të hasni kur transferoni skriptet powershell nga Windows në Linux?
sqlcmd vs Invoke-SqlCmd
Më lejoni t'ju kujtoj ndryshimin kryesor midis tyre. Shërbimi i vjetër i mirë sqlcmd Ai gjithashtu funksionon nën Linux, me funksionalitet pothuajse identik. Ne e kalojmë pyetjen për të ekzekutuar -Q, skedarin hyrës si -i dhe daljen si -o. Por emrat e skedarëve, natyrisht, janë të ndjeshëm ndaj rasteve. Nëse përdorni -i, atëherë në skedar shkruani në fund:
GO
EXIT
Nëse nuk ka EXIT në fund, atëherë sqlcmd do të vazhdojë të presë për hyrje, dhe nëse më parë EXIT nuk do GO, atëherë komanda e fundit nuk do të funksionojë. Skedari i daljes përmban të gjitha rezultatet, zgjedhjet, mesazhet, printimet, etj.
Invoke-SqlCmd prodhon rezultatin si DataSet, DataTables ose DataRows. Prandaj, nëse përpunoni rezultatin e një përzgjedhjeje të thjeshtë, mund ta përdorni sqlcmd, pasi të keni analizuar prodhimin e tij, është pothuajse e pamundur të nxirret diçka komplekse: për këtë ekziston Invoke-SqlCmd. Por kjo skuadër ka edhe batutat e veta:
Nëse i transferoni asaj një skedar nëpërmjet -InputFile, Pastaj EXIT nuk nevojitet, për më tepër, prodhon një gabim sintaksor
-OutputFile jo, komanda ju kthen rezultatin si objekt
Ekzistojnë dy sintaksa për të specifikuar një server: -ServerInstance -Emri i përdoruesit -Fjalëkalimi -Baza e të dhënave dhe përmes -ConnectionString. Mjaft e çuditshme, në rastin e parë nuk është e mundur të specifikohet një port tjetër përveç 1433.
prodhimi i tekstit, shkruani PRINT, i cili thjesht "kapet" sqlcmdpër Invoke-SqlCmdështë një problem
sqlcmd ka zëvendësim të ndryshoreve duke përdorur -v, për shembull si kjo:
# $conn содержит начало команды sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res
-v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmd
Në skriptin SQL ne përdorim zëvendësime:
set @spid=$(spid)
set @age=$(age)
Pra ja ku është. Në *nix Zëvendësimet e variablave nuk funksionojnë... Parametri -v injoruar. U Invoke-SqlCmd injoruar -Ndryshoret. Megjithëse parametri që specifikon vetë variablat injorohet, vetë zëvendësimet funksionojnë—mund të përdorni çdo variabël nga Shell. Sidoqoftë, unë u ofendova nga variablat dhe vendosa të mos varem fare prej tyre dhe veprova në mënyrë të vrazhdë dhe primitive, pasi skriptet SQL janë të shkurtra:
Ky, siç e kuptoni, është një test tashmë nga versioni Unix.
Ngarkimi i skedarëve
Në versionin e Windows, çdo operacion u shoqërua me një auditim: ne ekzekutuam sqlcmd, morëm një lloj abuzimi në skedarin e daljes, bashkëngjitëm këtë skedar në pllakën e kontrollit. Për fat të mirë, serveri SQL punoi në të njëjtin server si Jenkins, u bë diçka si kjo:
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
Kështu, ne e gëlltisim plotësisht skedarin BCP dhe e futim atë në fushën nvarchar(max) të tabelës së auditimit. Sigurisht, i gjithë ky sistem u shpërbë, sepse në vend të një serveri SQL mora RDS, dhe BULK INSERT nuk funksionon fare përmes UNC për shkak të një përpjekjeje për të marrë një bllokim ekskluziv në një skedar, dhe me RDS kjo përgjithësisht është e dënuar nga vetë fillimi. Kështu që vendosa të ndryshoj modelin e sistemit, duke ruajtur auditimin rresht pas rreshti:
CREATE TABLE AuditOut (
ID int NULL,
TextLine nvarchar(max) NULL,
n int IDENTITY(1,1) PRIMARY KEY
)
Dhe shkruani në këtë tabelë si kjo:
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()
}
Për të zgjedhur përmbajtjen, duhet të zgjidhni sipas ID-së, duke zgjedhur me radhë n (identitet).
Në artikullin tjetër do të hyj në më shumë detaje se si ndërvepron e gjithë kjo me Jenkins.