Այս հոդվածը զուտ գործնական է և նվիրված է իմ տխուր պատմությանը
Պատրաստվում է Zero Touch PROD RDS-ի համար (MS SQL), որի մասին մեր բոլոր ականջները բզզում էին, ես պատրաստեցի ավտոմատացման ներկայացում (POC - Proof Of Concept)՝ powershell սկրիպտների մի շարք: Շնորհանդեսից հետո, երբ բուռն, տեւական ծափերը մարեցին՝ վերածվելով չդադարող ծափերի, նրանք ինձ ասացին՝ այս ամենը լավ է, բայց միայն գաղափարական նկատառումներով, մեր Ջենքինսի բոլոր ստրուկներն աշխատում են Linux-ով։
Սա հնարավո՞ր է: Վերցնե՞լ Windows-ի տակից այսքան տաք, լամպի DBA-ն և կպցնել այն Linux-ի տակ գտնվող Powershell-ի բուն ջերմության մեջ: Սա դաժան չէ՞։
Ես ստիպված էի ընկղմվել տեխնոլոգիաների այս տարօրինակ համադրության մեջ։ Իհարկե, իմ բոլոր 30+ սցենարները դադարեցին աշխատել։ Ի զարմանս ինձ՝ մեկ աշխատանքային օրվա ընթացքում հաջողվեց ամեն ինչ շտկել։ Ես գրում եմ տաք հետապնդման մեջ: Այսպիսով, ի՞նչ որոգայթների կարող եք հանդիպել powershell սկրիպտները Windows-ից Linux տեղափոխելիս:
sqlcmd vs Invoke-SqlCmd
Հիշեցնեմ նրանց հիմնական տարբերությունը. Լավ հին կոմունալ sqlcmd Այն նաև աշխատում է Linux-ի ներքո՝ գրեթե նույնական ֆունկցիոնալությամբ: Հարցումը կատարում ենք -Q, մուտքային ֆայլը՝ -i, իսկ ելքը՝ -o: Բայց ֆայլերի անունները, իհարկե, մեծատառերի զգայուն են: Եթե օգտագործում եք -i, ապա ֆայլում վերջում գրեք.
GO
EXIT
Եթե վերջում EXIT չկա, ապա sqlcmd-ը կշարունակի սպասել մուտքագրմանը, և եթե նախկինում Ելք չի լինի GO, ապա վերջին հրամանը չի աշխատի։ Ելքային ֆայլը պարունակում է բոլոր արդյունքները, ընտրվածները, հաղորդագրությունները, տպագրությունը և այլն:
Invoke-SqlCmd-ն արդյունք է տալիս որպես DataSet, DataTables կամ DataRows: Հետեւաբար, եթե դուք մշակում եք պարզ ընտրության արդյունքը, կարող եք օգտագործել sqlcmd, վերլուծելով դրա արդյունքը, գրեթե անհնար է բարդ բան դուրս բերել. դրա համար կա Invoke-SqlCmd. Բայց այս թիմն ունի նաև իր կատակները.
Եթե դուք ֆայլ եք փոխանցում նրան միջոցով -InputFile, Հետո Ելք անհրաժեշտ չէ, ավելին, այն առաջացնում է շարահյուսական սխալ
- OutputFile ոչ, հրամանը ձեզ վերադարձնում է արդյունքը որպես օբյեկտ
Սերվերը նշելու երկու շարահյուսություն կա. -ServerInstance -Օգտվողի անուն -Գաղտնաբառ -Տվյալների բազա և միջոցով -ConnectionString. Տարօրինակ կերպով, առաջին դեպքում հնարավոր չէ նշել 1433-ից այլ նավահանգիստ:
տեքստի ելք, տպեք PRINT, որը պարզապես «բռնված» է sqlcmdհամար Invoke-SqlCmdխնդիր է
sqlcmd-ն ունի փոփոխական փոխարինում՝ օգտագործելով -v, օրինակ՝ այսպես.
# $conn содержит начало команды sqlcmd
$cmd = $conn + " -i D:appsSlaveJobsKillSpid.sql -o killspid.res
-v spid =`"" + $spid + "`" -v age =`"" + $age + "`""
Invoke-Expression $cmd
SQL սկրիպտում մենք օգտագործում ենք փոխարինումներ.
set @spid=$(spid)
set @age=$(age)
Այսպիսով, ահա այն: * nix-ում Փոփոխական փոխարինումները չեն աշխատում. Պարամետր -v անտեսված. U Invoke-SqlCmd անտեսված -Փոփոխականներ. Չնայած այն պարամետրը, որը սահմանում է հենց փոփոխականները, անտեսվում է, փոխարինումներն իրենք են աշխատում. կարող եք օգտագործել Shell-ի ցանկացած փոփոխական: Այնուամենայնիվ, ես վիրավորված էի փոփոխականներից և որոշեցի ընդհանրապես կախված չլինել դրանցից և գործեցի կոպիտ և պարզունակ, քանի որ SQL սցենարները կարճ են.
Սա, ինչպես հասկանում եք, արդեն թեստ է Unix տարբերակից։
Ֆայլերի բեռնում
Windows-ի տարբերակում ցանկացած գործողություն ուղեկցվում էր աուդիտով՝ մենք գործարկեցինք sqlcmd, ստացանք ինչ-որ չարաշահում ելքային ֆայլում, կցեցինք այս ֆայլը աուդիտի ափսեին: Բարեբախտաբար, SQL սերվերը աշխատում էր նույն սերվերի վրա, ինչ Ջենքինսը, դա արվեց հետևյալ կերպ.
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
Այսպիսով, մենք ամբողջությամբ կուլ ենք տալիս BCP ֆայլը և այն տեղափոխում աուդիտի աղյուսակի nvarchar(max) դաշտ: Իհարկե, այս ամբողջ համակարգը փլուզվեց, քանի որ SQL սերվերի փոխարեն ես ստացա RDS, իսկ BULK INSERT-ն ընդհանրապես չի աշխատում UNC-ի միջոցով՝ ֆայլի վրա բացառիկ կողպելու փորձի պատճառով, և RDS-ով դա ընդհանրապես դատապարտված է: հենց սկիզբը. Այսպիսով, ես որոշեցի փոխել համակարգի դիզայնը, պահելով աուդիտը տող առ տող.
CREATE TABLE AuditOut (
ID int NULL,
TextLine nvarchar(max) NULL,
n int IDENTITY(1,1) PRIMARY KEY
)
Եվ այս աղյուսակում գրեք այսպես.
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()
}
Բովանդակություն ընտրելու համար անհրաժեշտ է ընտրել ըստ ID-ի՝ ընտրելով n (ինքնություն) հերթականությունը:
Հաջորդ հոդվածում ես ավելի մանրամասն կանդրադառնամ, թե ինչպես է այս ամենը փոխազդում Ջենկինսի հետ: