Աշխատում է MS SQL-ի հետ Powershell-ից Linux-ում

Այս հոդվածը զուտ գործնական է և նվիրված է իմ տխուր պատմությանը

Պատրաստվում է Zero Touch PROD RDS-ի համար (MS SQL), որի մասին մեր բոլոր ականջները բզզում էին, ես պատրաստեցի ավտոմատացման ներկայացում (POC - Proof Of Concept)՝ powershell սկրիպտների մի շարք: Շնորհանդեսից հետո, երբ բուռն, տեւական ծափերը մարեցին՝ վերածվելով չդադարող ծափերի, նրանք ինձ ասացին՝ այս ամենը լավ է, բայց միայն գաղափարական նկատառումներով, մեր Ջենքինսի բոլոր ստրուկներն աշխատում են Linux-ով։

Սա հնարավո՞ր է: Վերցնե՞լ Windows-ի տակից այսքան տաք, լամպի DBA-ն և կպցնել այն Linux-ի տակ գտնվող Powershell-ի բուն ջերմության մեջ: Սա դաժան չէ՞։

Աշխատում է MS SQL-ի հետ Powershell-ից Linux-ում
Ես ստիպված էի ընկղմվել տեխնոլոգիաների այս տարօրինակ համադրության մեջ։ Իհարկե, իմ բոլոր 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 խնդիր է
  • Եվ ամենակարևորը. Ամենայն հավանականությամբ, ձեր Linux-ը չունի այս cmdlet-ը:

Եվ սա է հիմնական խնդիրը։ Միայն մարտին այս cmdlet-ը հասանելի դարձավ ոչ Windows պլատֆորմների համար, և վերջապես մենք կարող ենք առաջ շարժվել:

Փոփոխական փոխարինում

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 սցենարները կարճ են.

# 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"

Սա, ինչպես հասկանում եք, արդեն թեստ է 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 (ինքնություն) հերթականությունը:

Հաջորդ հոդվածում ես ավելի մանրամասն կանդրադառնամ, թե ինչպես է այս ամենը փոխազդում Ջենկինսի հետ:

Source: www.habr.com

Добавить комментарий