Laporan Harian Status Mesin Virtual dengan R dan PowerShell


Entri


Hari yang baik Selama setengah tahun sekarang kami telah menjalankan skrip (lebih tepatnya, serangkaian skrip) yang menghasilkan laporan tentang keadaan mesin virtual (dan tidak hanya). Saya memutuskan untuk membagikan pengalaman pembuatan dan kode itu sendiri. Saya mengandalkan kritik dan fakta bahwa materi ini mungkin berguna bagi seseorang.


Perlu pembentukan


Kami memiliki banyak mesin virtual (sekitar 1500 VM yang didistribusikan melalui vCenter ke-3). Yang baru dibuat dan yang lama sering dihapus. Untuk menjaga ketertiban, beberapa bidang khusus ditambahkan ke vCenter untuk membagi VM menjadi Subsistem, menunjukkan apakah mereka diuji, serta oleh siapa dan kapan. Faktor manusia telah mengarah pada fakta bahwa lebih dari setengah mobil dibiarkan kosong, yang mempersulit pekerjaan. Sekali setiap enam bulan, seseorang menjadi panik, mulai bekerja memperbarui data ini, tetapi hasilnya tidak lagi relevan selama satu setengah minggu.
Saya akan segera mengklarifikasi bahwa semua orang memahami bahwa harus ada aplikasi untuk membuat mesin, proses pembuatannya, dll. dll. Dan sementara semua proses ini diikuti secara ketat dan teratur. Sayangnya, ini bukan masalahnya dengan kami, tetapi ini bukan subjek dari artikel :)


Secara umum, diputuskan untuk mengotomatiskan verifikasi kebenaran pengisian bidang.
Kami memutuskan bahwa surat harian dengan daftar mesin yang tidak diisi dengan benar untuk semua insinyur yang bertanggung jawab dan atasan mereka akan menjadi awal yang baik.


Pada titik ini, salah satu rekan sudah menerapkan skrip PowerShell, yang setiap hari sesuai jadwal mengumpulkan informasi pada semua mesin semua vCenter-s dan membentuk 3 dokumen csv (masing-masing dalam vCenter sendiri), yang diletakkan di disk bersama. Diputuskan untuk mengambil skrip ini sebagai dasar dan menambahnya dengan cek menggunakan bahasa R, yang saya punya pengalaman dengannya.


Dalam proses finalisasi, solusinya ditumbuhi dengan memberi informasi melalui surat, database dengan tabel utama dan historis (lebih lanjut tentang ini nanti), serta menganalisis log vSphere untuk menemukan pembuat sebenarnya vm dan waktu pembuatannya.


Untuk pengembangan, IDE RStudio Desktop dan PowerShell ISE digunakan.


Script diluncurkan dari mesin virtual Windows biasa.


Deskripsi logika umum.


Logika umum skrip adalah sebagai berikut.


  • Kami mengumpulkan data pada mesin virtual menggunakan skrip PowerShell, yang disebut melalui R, hasilnya digabungkan menjadi satu csv. Interaksi terbalik antar bahasa dilakukan dengan cara yang sama. (itu mungkin untuk mengarahkan data langsung dari R ke PowerShell dalam bentuk variabel, tetapi sulit, dan bahkan dengan csv menengah lebih mudah untuk men-debug dan berbagi hasil antara dengan seseorang).
  • Menggunakan R, kami membentuk parameter yang valid untuk bidang yang nilainya kami periksa. - Kami sedang membentuk dokumen kata yang akan berisi nilai-nilai bidang ini untuk dimasukkan ke dalam surat informasi yang akan menjadi jawaban untuk pertanyaan dari rekan kerja "Tidak baik, tapi bagaimana saya harus mengisi ini?"
  • Kami memuat data pada semua VM dari csv menggunakan R, membentuk kerangka data, menghapus bidang yang tidak perlu dan membentuk dokumen informasi xlsx yang akan berisi informasi ringkasan tentang semua VM yang kami unggah ke sumber daya bersama.
  • Untuk kerangka data untuk semua VM, kami menerapkan semua pemeriksaan untuk kebenaran mengisi bidang dan membentuk tabel yang hanya berisi VM dengan bidang yang tidak diisi dengan benar (dan hanya bidang ini).
  • Daftar VM yang dihasilkan dikirim ke skrip PowerShell lain, yang akan melihat log vCenter untuk acara pembuatan VM, yang akan memungkinkan Anda untuk menentukan perkiraan waktu pembuatan VM dan pembuat yang dimaksud. Ini adalah kasus ketika tidak ada yang mengaku mobilnya. Skrip ini tidak berfungsi dengan cepat, terutama jika ada banyak log, jadi kami hanya melihat pada 2 minggu terakhir, dan kami juga menggunakan alur kerja, yang memungkinkan Anda untuk mencari informasi pada beberapa VM secara bersamaan. Dalam contoh skrip, ada komentar terperinci tentang mekanisme ini. Hasilnya ditambahkan ke csv, yang kembali dimuat ke R.
  • Kami membentuk dokumen xlsx yang diformat dengan indah di mana bidang yang tidak diisi dengan benar akan disorot dalam warna merah, filter akan diterapkan ke beberapa kolom, dan kolom tambahan berisi dugaan pembuat dan waktu pembuatan VM akan ditunjukkan.
  • Kami membentuk email, tempat kami meletakkan dokumen yang menggambarkan nilai-nilai bidang yang valid, serta tabel dengan salah mengisi. Dalam teks kami menunjukkan jumlah total VM yang dibuat secara tidak benar, tautan ke sumber daya bersama dan gambar motivasi. Jika tidak ada VM yang tidak diisi dengan benar, kami mengirim surat lain dengan gambar motivasi yang lebih menyenangkan.
  • Kami mencatat data pada semua VM di database SQL Server, dengan mempertimbangkan mekanisme tabel historis yang diterapkan (mekanisme yang sangat menarik - yang lebih detail)

Skrip


File utama dengan kode untuk R
#     (       ) setwd("C:\\Scripts\\getVm") ####    #### library(tidyverse) library(xlsx) library(mailR) library(rmarkdown) #####         ##### source(file = "const.R", local = T, encoding = "utf-8") #        ,  . if (file.exists(filenameVmCreationRules)) {file.remove(filenameVmCreationRules)} ####       render("VM_name_rules.Rmd", output_format = word_document(), output_file = filenameVmCreationRules) #        ,   if (file.exists(allVmXlsxPath)) {file.remove(allVmXlsxPath)} ####       PowerShell .    csv. system(paste0("powershell -File ", getVmPsPath)) #  df fullXslx_df <- allVmXlsxPath %>% read.csv2(stringsAsFactors = FALSE) #     full_df <- fullXslx_df %>% mutate( #       ,    ,      , isSubsystemCorrect = Subsystem %>% gsub("[[:space:]]", "", .) %>% str_split(., ",") %>% map(function(x) (all(x %in% AllowedValues$Subsystem))) %>% as.logical(), isOwnerCorrect = Owner %in% AllowedValues$Owner, isCategoryCorrect = Category %in% AllowedValues$Category, isCreatorCorrect = (!is.na(Creator) & Creator != ''), isCreation.DateCorrect = map(Creation.Date, IsDate) ) #        ,  . if (file.exists(filenameAll)) {file.remove(filenameAll)} ####  xslx    #### #      full_df %>% write.xlsx(file=filenameAll, sheetName=names[1], col.names=TRUE, row.names=FALSE, append=FALSE) ####  xslx      #### #  df incorrect_df <- full_df %>% select(VM.Name, IP.s, Owner, Subsystem, Creator, Category, Creation.Date, isOwnerCorrect, isSubsystemCorrect, isCategoryCorrect, isCreatorCorrect, vCenter.Name) %>% filter(isSubsystemCorrect == F | isOwnerCorrect == F | isCategoryCorrect == F | isCreatorCorrect == F) #        ,  . if (file.exists(filenameIncVM)) {file.remove(filenameIncVM)} #   VM     csv incorrect_df %>% select(VM.Name) %>% write_csv2(path = filenameIncVM, append = FALSE) #      incorrect_df_filtered <- incorrect_df %>% select(VM.Name, IP.s, Owner, Subsystem, Category, Creator, vCenter.Name, Creation.Date ) #    numberOfRows <- nrow(incorrect_df) ####   #### #        ,  . #   -     if (numberOfRows > 0) { #       ,  . if (file.exists(creatorsFilePath)) {file.remove(creatorsFilePath)} #  PowerShell ,     VM.    csv. system(paste0("powershell -File ", getCreatorsPath)) #     creators_df <- creatorsFilePath %>% read.csv2(stringsAsFactors = FALSE) #     ,       incorrect_df_filtered <- incorrect_df_filtered %>% select(VM.Name, IP.s, Owner, Subsystem, Category, Creator, vCenter.Name, Creation.Date ) %>% left_join(creators_df, by = "VM.Name") %>% rename(` ` = CreatedBy, `  ` = CreatedOn) #    emailBody <- paste0( '<html> <h3> ,  .</h3> <p>           H:  :<p> <p>\\\\server.ru\\VM\\', sourceFileFormat, '</p> <p>      <strong> </strong> .   <strong>', numberOfRows,'</strong>.</p> <p>   2  . <strong> </strong>  <strong>  </strong>,     vCenter   2 </p> <p>        .      </p> <p><img src="data/meme.jpg"></p> </html>' ) #    if (file.exists(filenameIncorrect)) {file.remove(filenameIncorrect)} #       .. source(file = "email.R", local = T, encoding = "utf-8") ####       #### send.mail(from = emailParams$from, to = emailParams$to, subject = "    ", body = emailBody, encoding = "utf-8", html = TRUE, inline = TRUE, smtp = emailParams$smtpParams, authenticate = TRUE, send = TRUE, attach.files = c(filenameIncorrect, filenameVmCreationRules), debug = FALSE) ####   ,      #### } else { #    emailBody <- paste0( '<html> <h3> ,  </h3> <p>           H:  :<p> <p>\\\\server.ru\\VM\\', sourceFileFormat, '</p> <p>,   ,     </p> <p><img src="data/meme_correct.jpg"></p> </html>' ) ####      VM #### send.mail(from = emailParams$from, to = emailParams$to, subject = " ", body = emailBody, encoding = "utf-8", html = TRUE, inline = TRUE, smtp = emailParams$smtpParams, authenticate = TRUE, send = TRUE, debug = FALSE) } #######     ##### source(file = "DB.R", local = T, encoding = "utf-8") 

Script untuk mendapatkan daftar vm di PowerShell
 #       $vCenterNames = @( "vcenter01", "vcenter02", "vcenter03" ) $vCenterUsername = "myusername" $vCenterPassword = "mypassword" $filename = "C:\Scripts\getVm\data\allvm\all-vm-$(get-date -f yyyy-MM-dd).csv" $destinationSMB = "\\server.ru\myfolder$\vm" $IP0="" $IP1="" $IP2="" $IP3="" $IP4="" $IP5="" #    vCenter,    .  ,      (, ) Connect-VIServer -Server $vCenterNames -User $vCenterUsername -Password $vCenterPassword write-host "" #       vCenter- function Get-VMinventory { #       ,   $AllVM = Get-VM | Sort Name $cnt = $AllVM.Count $count = 1 #            foreach ($vm in $AllVM) { $StartTime = $(get-date) $IP0 = $vm.Guest.IPAddress[0] $IP1 = $vm.Guest.IPAddress[1] $IP2 = $vm.Guest.IPAddress[2] $IP3 = $vm.Guest.IPAddress[3] $IP4 = $vm.Guest.IPAddress[4] $IP5 = $vm.Guest.IPAddress[5] If ($IP0 -ne $null) {If ($IP0.Contains(":") -ne 0) {$IP0=""}} If ($IP1 -ne $null) {If ($IP1.Contains(":") -ne 0) {$IP1=""}} If ($IP2 -ne $null) {If ($IP2.Contains(":") -ne 0) {$IP2=""}} If ($IP3 -ne $null) {If ($IP3.Contains(":") -ne 0) {$IP3=""}} If ($IP4 -ne $null) {If ($IP4.Contains(":") -ne 0) {$IP4=""}} If ($IP5 -ne $null) {If ($IP5.Contains(":") -ne 0) {$IP5=""}} $cluster = $vm | Get-Cluster | Select-Object -ExpandProperty name $Bootime = $vm.ExtensionData.Runtime.BootTime $TotalHDDs = $vm.ProvisionedSpaceGB -as [int] $CreationDate = $vm.CustomFields.Item("CreationDate") -as [string] $Creator = $vm.CustomFields.Item("Creator") -as [string] $Category = $vm.CustomFields.Item("Category") -as [string] $Owner = $vm.CustomFields.Item("Owner") -as [string] $Subsystem = $vm.CustomFields.Item("Subsystem") -as [string] $IPS = $vm.CustomFields.Item("IP") -as [string] $vCPU = $vm.NumCpu $CorePerSocket = $vm.ExtensionData.config.hardware.NumCoresPerSocket $Sockets = $vCPU/$CorePerSocket $Id = $vm.Id.Split('-')[2] -as [int] #       $Vmresult = New-Object PSObject $Vmresult | add-member -MemberType NoteProperty -Name "Id" -Value $Id $Vmresult | add-member -MemberType NoteProperty -Name "VM Name" -Value $vm.Name $Vmresult | add-member -MemberType NoteProperty -Name "Cluster" -Value $cluster $Vmresult | add-member -MemberType NoteProperty -Name "Esxi Host" -Value $VM.VMHost $Vmresult | add-member -MemberType NoteProperty -Name "IP Address 1" -Value $IP0 $Vmresult | add-member -MemberType NoteProperty -Name "IP Address 2" -Value $IP1 $Vmresult | add-member -MemberType NoteProperty -Name "IP Address 3" -Value $IP2 $Vmresult | add-member -MemberType NoteProperty -Name "IP Address 4" -Value $IP3 $Vmresult | add-member -MemberType NoteProperty -Name "IP Address 5" -Value $IP4 $Vmresult | add-member -MemberType NoteProperty -Name "IP Address 6" -Value $IP5 $Vmresult | add-member -MemberType NoteProperty -Name "vCPU" -Value $vCPU $Vmresult | Add-Member -MemberType NoteProperty -Name "CPU Sockets" -Value $Sockets $Vmresult | Add-Member -MemberType NoteProperty -Name "Core per Socket" -Value $CorePerSocket $Vmresult | add-member -MemberType NoteProperty -Name "RAM (GB)" -Value $vm.MemoryGB $Vmresult | add-member -MemberType NoteProperty -Name "Total-HDD (GB)" -Value $TotalHDDs $Vmresult | add-member -MemberType NoteProperty -Name "Power State" -Value $vm.PowerState $Vmresult | add-member -MemberType NoteProperty -Name "OS" -Value $VM.ExtensionData.summary.config.guestfullname $Vmresult | Add-Member -MemberType NoteProperty -Name "Boot Time" -Value $Bootime $Vmresult | add-member -MemberType NoteProperty -Name "VMTools Status" -Value $vm.ExtensionData.Guest.ToolsStatus $Vmresult | add-member -MemberType NoteProperty -Name "VMTools Version" -Value $vm.ExtensionData.Guest.ToolsVersion $Vmresult | add-member -MemberType NoteProperty -Name "VMTools Version Status" -Value $vm.ExtensionData.Guest.ToolsVersionStatus $Vmresult | add-member -MemberType NoteProperty -Name "VMTools Running Status" -Value $vm.ExtensionData.Guest.ToolsRunningStatus $Vmresult | add-member -MemberType NoteProperty -Name "Creation Date" -Value $CreationDate $Vmresult | add-member -MemberType NoteProperty -Name "Creator" -Value $Creator $Vmresult | add-member -MemberType NoteProperty -Name "Category" -Value $Category $Vmresult | add-member -MemberType NoteProperty -Name "Owner" -Value $Owner $Vmresult | add-member -MemberType NoteProperty -Name "Subsystem" -Value $Subsystem $Vmresult | add-member -MemberType NoteProperty -Name "IP's" -Value $IPS $Vmresult | add-member -MemberType NoteProperty -Name "vCenter Name" -Value $vm.Uid.Split('@')[1].Split(':')[0] #           .   ,      . $elapsedTime = $(get-date) - $StartTime $totalTime = "{0:HH:mm:ss}" -f ([datetime]($elapsedTime.Ticks*($cnt - $count))) clear-host Write-Host "Processing" $count "from" $cnt Write-host "Progress:" ([math]::Round($count/$cnt*100, 2)) "%" Write-host "You have about " $totalTime "for cofee" Write-host "" $count++ #  ,   ""       $Vmresult } } #         csv $allVm = Get-VMinventory | Export-CSV -Path $filename -NoTypeInformation -UseCulture -Force #         ,   ,  . try { Copy-Item $filename -Destination $destinationSMB -Force -ErrorAction SilentlyContinue } catch { $error | Export-CSV -Path $filename".error" -NoTypeInformation -UseCulture -Force } 

Script PowerShell mengeluarkan log dari pencipta mesin virtual dan tanggal pembuatannya
 #   ,      VM $VMfilePath = "C:\Scripts\getVm\creators_VM\creators_VM_$(get-date -f yyyy-MM-dd).csv" #   ,      $filePath = "C:\Scripts\getVm\data\creators\creators-$(get-date -f yyyy-MM-dd).csv" #   Workflow GetCreators-Wf { # ,        param([string[]]$VMfilePath) # ,     workflow $vCenterUsername = "myusername" $vCenterPassword = "mypassword" $daysToLook = 14 $start = (get-date).AddDays(-$daysToLook) $finish = get-date # ,     csv  ,       $UnknownUser = "UNKNOWN" $UnknownCreatedTime = "0000-00-00" #      ,      . $vCenterNames = @( "vcenter01", "vcenter02", "vcenter03" ) #   VM  csv     $list = Import-Csv $VMfilePath -UseCulture | select -ExpandProperty VM.Name # ,     ( 5   ) foreach -parallel ($row in $list) { #  ,       ,     $Using InlineScript { #      $StartTime = $(get-date) Write-Host "" Write-Host "Processing $Using:row started at $StartTime" Write-Host "" #    ,         $con = Connect-VIServer -Server $Using:vCenterNames -User $Using:vCenterUsername -Password $Using:vCenterPassword #   vm $vm = Get-VM -Name $Using:row #  2  .     ,  - .   , $Event = $vm | Get-VIEvent -Start $Using:start -Finish $Using:finish -Types Info | Where { $_.Gettype().Name -eq "VmBeingDeployedEvent" -or $_.Gettype().Name -eq "VmCreatedEvent" -or $_.Gettype().Name -eq "VmRegisteredEvent" -or $_.Gettype().Name -eq "VmClonedEvent"} # $Event = $vm | Get-VIEvent -Types Info | Where { $_.Gettype().Name -eq "VmBeingDeployedEvent" -or $_.Gettype().Name -eq "VmCreatedEvent" -or $_.Gettype().Name -eq "VmRegisteredEvent" -or $_.Gettype().Name -eq "VmClonedEvent"} #      ,      - If (($Event | Measure-Object).Count -eq 0){ $User = $Using:UnknownUser $Created = $Using:UnknownCreatedTime $CreatedFormat = $Using:UnknownCreatedTime } Else { If ($Event.Username -eq "" -or $Event.Username -eq $null) { $User = $Using:UnknownUser } Else { $User = $Event.Username } # Else $CreatedFormat = $Event.CreatedTime #     ,      ,   .      . $Created = $Event.CreatedTime.ToString('yyyy-MM-dd') } # Else Write-Host "Creator for $vm is $User. Creating object." #  .  . $Vmresult = New-Object PSObject $Vmresult | add-member -MemberType NoteProperty -Name "VM Name" -Value $vm.Name $Vmresult | add-member -MemberType NoteProperty -Name "CreatedBy" -Value $User $Vmresult | add-member -MemberType NoteProperty -Name "CreatedOn" -Value $CreatedFormat $Vmresult | add-member -MemberType NoteProperty -Name "CreatedOnFormat" -Value $Created #   $Vmresult } # Inline } # ForEach } $Creators = GetCreators-Wf $VMfilePath #     $Creators | select 'VM Name', CreatedBy, CreatedOn | Export-Csv -Path $filePath -NoTypeInformation -UseCulture -Force Write-Host "CSV generetion finisghed at $(get-date). PROFIT" 

Pustaka xlsx pantas mendapatkan perhatian khusus, yang memungkinkan untuk membuat lampiran ke surat diformat dengan jelas (seperti yang disukai manual), dan bukan hanya tabel csv.


Membuat dokumen xlsx yang indah dengan daftar mesin yang salah isi
 #    #   : "xls"  "xlsx" wb<-createWorkbook(type="xlsx") #         TABLE_ROWNAMES_STYLE <- CellStyle(wb) + Font(wb, isBold=TRUE) TABLE_COLNAMES_STYLE <- CellStyle(wb) + Font(wb, isBold=TRUE) + Alignment(wrapText=TRUE, horizontal="ALIGN_CENTER") + Border(color="black", position=c("TOP", "BOTTOM"), pen=c("BORDER_THIN", "BORDER_THICK")) #    sheet <- createSheet(wb, sheetName = names[2]) #   addDataFrame(incorrect_df_filtered, sheet, startRow=1, startColumn=1, row.names=FALSE, byrow=FALSE, colnamesStyle = TABLE_COLNAMES_STYLE, rownamesStyle = TABLE_ROWNAMES_STYLE) #  ,     autoSizeColumn(sheet = sheet, colIndex=c(1:ncol(incorrect_df))) #   addAutoFilter(sheet, cellRange = "C1:G1") #   fo2 <- Fill(foregroundColor="red") cs2 <- CellStyle(wb, fill = fo2, dataFormat = DataFormat("@")) #              rowsOwner <- getRows(sheet, rowIndex = (which(!incorrect_df$isOwnerCorrect) + 1)) cellsOwner <- getCells(rowsOwner, colIndex = which( colnames(incorrect_df_filtered) == "Owner" )) lapply(names(cellsOwner), function(x) setCellStyle(cellsOwner[[x]], cs2)) #              rowsSubsystem <- getRows(sheet, rowIndex = (which(!incorrect_df$isSubsystemCorrect) + 1)) cellsSubsystem <- getCells(rowsSubsystem, colIndex = which( colnames(incorrect_df_filtered) == "Subsystem" )) lapply(names(cellsSubsystem), function(x) setCellStyle(cellsSubsystem[[x]], cs2)) #    rowsCategory <- getRows(sheet, rowIndex = (which(!incorrect_df$isCategoryCorrect) + 1)) cellsCategory <- getCells(rowsCategory, colIndex = which( colnames(incorrect_df_filtered) == "Category" )) lapply(names(cellsCategory), function(x) setCellStyle(cellsCategory[[x]], cs2)) #  rowsCreator <- getRows(sheet, rowIndex = (which(!incorrect_df$isCreatorCorrect) + 1)) cellsCreator <- getCells(rowsCreator, colIndex = which( colnames(incorrect_df_filtered) == "Creator" )) lapply(names(cellsCreator), function(x) setCellStyle(cellsCreator[[x]], cs2)) #   saveWorkbook(wb, filenameIncorrect) 

Outputnya kira-kira seperti ini:




Ada juga nuansa yang menarik dalam mengatur Windows scheduller. Tidak berhasil untuk mengambil hak dan parameter pengaturan yang benar sehingga semuanya akan dimulai sebagaimana mestinya. Akibatnya, pustaka R ditemukan, yang dengan sendirinya membuat tugas untuk menjalankan skrip R dan bahkan tidak melupakan file log. Kemudian Anda dapat memperbaiki tugas dengan pena.


Sepotong kode R dengan dua contoh yang membuat tugas di Penjadwal Windows
 library(taskscheduleR) myscript <- file.path(getwd(), "all_vm.R") ##    62  taskscheduler_create(taskname = "getAllVm", rscript = myscript, schedule = "ONCE", starttime = format(Sys.time() + 62, "%H:%M")) ##      09:10 taskscheduler_create(taskname = "getAllVmDaily", rscript = myscript, schedule = "WEEKLY", days = c("MON", "TUE", "WED", "THU", "FRI"), starttime = "02:00") ##   taskscheduler_delete(taskname = "getAllVm") taskscheduler_delete(taskname = "getAllVmDaily") #   ( 4 ) tail(readLines("all_vm.log"), sep ="\n", n = 4) 

Secara terpisah, tentang database


Setelah menyiapkan skrip, pertanyaan lain mulai muncul. Sebagai contoh, saya ingin mencari tanggal kapan VM dihapus, dan log di vCenter sudah dipakai. Karena skrip menempatkan file ke folder setiap hari dan tidak membersihkannya (kami membersihkannya dengan tangan kami ketika kami ingat), Anda dapat melihat file lama dan menemukan file pertama di mana VM ini tidak ada. Tapi itu tidak keren.


Saya ingin membuat database historis.


Fungsionalitas MS SQL SERVER datang ke bantuan - tabel temporal versi sistem. Biasanya diterjemahkan sebagai tabel sementara (non-sementara).


Anda dapat membaca secara detail di dokumentasi resmi Microsoft .


Singkatnya, kita membuat tabel, kita mengatakan bahwa kita akan memilikinya dengan versi dan SQL Server membuat 2 kolom datetime tambahan dalam tabel ini (tanggal catatan dibuat dan tanggal catatan kadaluwarsa) dan tabel tambahan di mana perubahan akan ditulis. Sebagai hasilnya, kami memperoleh informasi yang relevan dan, melalui pertanyaan sederhana, contoh-contoh yang diberikan dalam dokumentasi, kami dapat melihat siklus hidup mesin virtual tertentu atau keadaan semua VM pada titik waktu tertentu.


Dalam hal kinerja, transaksi tulis ke tabel utama tidak akan selesai sampai transaksi tulis ke tabel sementara selesai. Yaitu pada tabel dengan sejumlah besar operasi penulisan, fungsi ini harus diterapkan dengan hati-hati, tetapi dalam kasus kami ini adalah hal yang sangat keren.


Agar mekanisme berfungsi dengan benar, perlu untuk menambahkan sepotong kecil kode pada R yang akan membandingkan tabel baru dengan data untuk semua VM dengan yang disimpan dalam database dan menulis hanya mengubah baris untuk itu. Kode ini tidak terlalu rumit, ia menggunakan library compareDF, tapi saya juga akan memberikannya di bawah ini.


Kode R untuk menulis data ke basis data
 #   library(odbc) library(compareDF) #   con <- dbConnect(odbc(), Driver = "ODBC Driver 13 for SQL Server", Server = DBParams$server, Database = DBParams$database, UID = DBParams$UID, PWD = DBParams$PWD, Port = 1433) ####    .   - . #### if (!dbExistsTable(con, DBParams$TblName)) { ####   #### create <- dbSendStatement( con, paste0( 'CREATE TABLE ', DBParams$TblName, '( [Id] [int] NOT NULL PRIMARY KEY CLUSTERED, [VM.Name] [varchar](255) NULL, [Cluster] [varchar](255) NULL, [Esxi.Host] [varchar](255) NULL, [IP.Address.1] [varchar](255) NULL, [IP.Address.2] [varchar](255) NULL, [IP.Address.3] [varchar](255) NULL, [IP.Address.4] [varchar](255) NULL, [IP.Address.5] [varchar](255) NULL, [IP.Address.6] [varchar](255) NULL, [vCPU] [int] NULL, [CPU.Sockets] [int] NULL, [Core.per.Socket] [int] NULL, [RAM..GB.] [int] NULL, [Total.HDD..GB.] [int] NULL, [Power.State] [varchar](255) NULL, [OS] [varchar](255) NULL, [Boot.Time] [varchar](255) NULL, [VMTools.Status] [varchar](255) NULL, [VMTools.Version] [int] NULL, [VMTools.Version.Status] [varchar](255) NULL, [VMTools.Running.Status] [varchar](255) NULL, [Creation.Date] [varchar](255) NULL, [Creator] [varchar](255) NULL, [Category] [varchar](255) NULL, [Owner] [varchar](255) NULL, [Subsystem] [varchar](255) NULL, [IP.s] [varchar](255) NULL, [vCenter.Name] [varchar](255) NULL, DateFrom datetime2 GENERATED ALWAYS AS ROW START NOT NULL, DateTo datetime2 GENERATED ALWAYS AS ROW END NOT NULL, PERIOD FOR SYSTEM_TIME (DateFrom, DateTo) ) ON [PRIMARY] WITH (SYSTEM_VERSIONING = ON (HISTORY_TABLE = ', DBParams$TblHistName,'));' ) ) #    dbClearResult(create) } # if ####     #### #  ,     allVM_db_con <- tbl(con, DBParams$TblName) ####   #### #     (   ) allVM_db <- allVM_db_con %>% select(c(-"DateTo", -"DateFrom")) %>% collect() #     .   Id #       -,   +,   -  + ctable_VM <- fullXslx_df %>% compare_df(allVM_db, c("Id")) ####   #### #  Id ,      remove_Id <- ctable_VM$comparison_df %>% filter(chng_type == "-") %>% select(Id) # ,    (   -     ) if (remove_Id %>% nrow() > 0) { #        delete <- dbSendStatement(con, paste0(' DELETE FROM ', DBParams$TblName, ' WHERE "Id"=? ') # paste ) # send #      dbBind(delete, remove_Id) #    dbClearResult(delete) } # if ####   #### #  ,  ,   . allVM_add <- ctable_VM$comparison_df %>% filter(chng_type == "+") %>% select(-chng_type) # ,   ,      (  -  ) if (allVM_add %>% nrow() > 0) { #       dbWriteTable(con, DBParams$TblName, allVM_add, overwrite = FALSE, append = TRUE) } # if ####     #### dbDisconnect(con) 

Total


Sebagai hasil dari pengenalan naskah, pesanan dipertahankan dan dipertahankan selama beberapa bulan. Terkadang VM yang salah mengisi muncul, tetapi skrip berfungsi sebagai pengingat yang baik dan VM langka masuk ke dalam daftar selama 2 hari berturut-turut.


Cadangan juga dibuat untuk analisis data historis.


Jelas bahwa banyak dari hal ini dapat direalisasikan bukan "di lutut", tetapi dengan perangkat lunak khusus, tetapi tugas itu menarik dan, bisa dikatakan, opsional.


Sekali lagi R terbukti menjadi bahasa universal yang indah, yang sempurna tidak hanya untuk memecahkan masalah statistik, tetapi juga bertindak sebagai "peletakan" yang sangat baik antara sumber data lainnya.


Source: https://habr.com/ru/post/id454400/


All Articles