Artikel ini menyediakan kode untuk membuat laporan rutin tentang keadaan drive penyimpanan EMC VNX dengan pendekatan alternatif dan riwayat pembuatan.
Saya mencoba menulis kode dengan komentar paling rinci dan satu file. Hanya ganti kata sandi Anda. Format data sumber juga ditunjukkan, jadi saya akan senang jika seseorang mencoba menerapkannya di rumah.

Latar belakang
Anda dapat melewati jika tidak menarik dari mana "kaki tumbuh" dari.
Kami memiliki pusat data. Tidak ada sistem penyimpanan yang sangat segar. Ada banyak sistem penyimpanan, kegagalan disk juga. Beberapa kali seminggu orang pergi ke pusat data dan mengganti drive di sistem penyimpanan. Keputusan untuk mengganti disk dilakukan setelah alarm dari sistem " Recommended disk replacement ".
Tidak ada yang luar biasa.

Tetapi baru-baru ini, masing-masing LUN yang dikumpulkan pada sistem penyimpanan ini dan disajikan ke lingkungan Virtual mulai mengalami penurunan yang serius. Setelah berbicara dengan dukungan teknis vendor, menjadi jelas bahwa disk sudah harus diubah tidak hanya ketika pesan alarm di atas muncul, tetapi juga ketika sejumlah besar pesan lain muncul bahwa sistem tidak mempertimbangkan kesalahan kritis.
Pemantauan SNMP oleh sistem penyimpanan ini tidak didukung. Anda perlu menggunakan perangkat lunak berpemilik mahal (kami tidak memilikinya), atau utilitas konsol NaviSECCli , yang perlu dihubungkan ke setiap pengontrol (ada dua di antaranya) dari setiap sistem penyimpanan, tetapi ini tidak terlalu diinginkan.
Diputuskan untuk mengotomatiskan koleksi log dan mencari kesalahan di dalamnya. Dan keputusan untuk mengganti disk harus diserahkan kepada insinyur yang bertanggung jawab berdasarkan hasil analisis laporan.
Langkah pertama
Awalnya, salah satu rekan saya menulis kode PowerShell yang melakukan hal berikut:
- Mengambil tabel input yang berisi alamat ip pengontrol penyimpanan;
- siklus pergi ke alamat ip pengendali A , lalu ke alamat ip pengendali B ;
- dalam proses, tambahan mewawancarai mereka untuk nomor seri disk;
- diproses semua baris log dan disaring untuk konten pesan yang dicari;
- membuat objek PowerShell dan dalam propertinya mengurai data yang diperlukan dari garis yang diperoleh di atas;
- menggabungkan semua objek yang dihasilkan ke dalam tabel yang dikeluarkan dalam bentuk csv.
Kode di bawah. Segera buat reservasi bahwa ia bekerja, tetapi kami telah memperkenalkan solusi alternatif.
Sumber PowerShellcd 'd:\Navisphere CLI\' $csv = "D:\VNX-IP.csv" $Filter1 = "name1" $Filter2 = "name2" $Filter3 = "name3" $Data = import-csv $csv -Delimiter ';' | Where {$_.cl -EQ $Filter1 -Or $_.cl -EQ $Filter2 -Or $_.cl -EQ $Filter3} | Sort-Object -Property @{Expression={$_.cl}; Ascending=$true}, @{Expression={$_.Name} ;Ascending=$true} #$Filter1 = "nameOfcl" #$Data = import-csv $csv -Delimiter ';' | Where {$_.Name -EQ $Filter1} $Data | select Name,IP,cl $yStart = (Get-Date).AddDays(-30).ToString('yyyy') $yEnd = (Get-Date).ToString('yyyy') $mStart = (Get-Date).AddDays(-30).ToString('MM') $mEnd = (Get-Date).ToString('MM') $dStart = (Get-Date).AddDays(-30).ToString('dd') $dEnd = (Get-Date).ToString('dd') #$start = (Get-Date).AddDays(-3).ToString('MM\/dd\/yy') #$end = (Get-Date).ToString('MM\/dd\/yy') $i = 1 $table = ForEach ($row in $Data) { Write-Host $row.Name -ForegroundColor "Yellow" Write-Host "SP A" Write-Host (Get-Date).ToString('HH:mm:ss') $txt = .\NaviSECCli.exe -scope 0 -h $row.newA -user myusername -password mypassword getlog -date $mStart/$dStart/$yStart $mEnd/$dEnd/$yEnd | Select-String -Pattern "\(820\)","\(803\)","\(801\)","\(920\)","\(901\)" ForEach ($n in $txt) { $x = $n -Split(' ') $disk = $x[3] + "_" + $x[5] + "_" + $x[7].Split("(")[0] $sn = (.\NaviSECCli.exe -scope 0 -h $row.newA -user myusername -password mypassword getdisk $disk -serial)[1] | %{$_ -replace "Serial Number: ",""} | %{$_ -replace "State: ",""} | %{$_ -replace " ",""} New-Object PSObject -Property @{ i = $i cl = $row.cl Storage = $row.Name SP = "A" Date = $x[0] Time = $x[1] Disk = $disk Error = (($n -Split('\['))[0] -Split('\)'))[1].Trim() eCode = (($n -Split('\('))[1] -Split('\)'))[0] SN = $sn } $i = $i + 1 } Write-Host "SP B" Write-Host (Get-Date).ToString('HH:mm:ss') $txt = .\NaviSECCli.exe -scope 0 -h $row.newB -user myusername -password mypassword getlog -date $mStart/$dStart/$yStart $mEnd/$dEnd/$yEnd | Select-String -Pattern "\(820\)","\(803\)","\(801\)","\(920\)","\(901\)" ForEach ($n in $txt) { $x = $n -Split(' ') $disk = $x[3] + "_" + $x[5] + "_" + $x[7].Split("(")[0] $sn = (.\NaviSECCli.exe -scope 0 -h $row.newA -user myusername -password mypassword getdisk $disk -serial)[1] | %{$_ -replace "Serial Number: ",""} | %{$_ -replace "State: ",""} | %{$_ -replace " ",""} New-Object PSObject -Property @{ i = $i cl = $row.cl Storage = $row.Name SP = "B" Date = $x[0] Time = $x[1] Disk = $disk Error = (($n -Split('\['))[0] -Split('\)'))[1].Trim() eCode = (($n -Split('\('))[1] -Split('\)'))[0] SN = $sn } $i = $i + 1 } Write-Host " " } $table | select i,cl,Storage,SP,Date,Time,Disk,Error,eCode,SN | Export-Csv -Path 'd:\VNX-Errors.csv' -NoTypeInformation -UseCulture -Encoding UTF8
Semuanya baik-baik saja, yang tersisa adalah menambahkan "gloss" dalam bentuk pengiriman surat secara otomatis ke rekan-rekan yang tertarik dan format minimal csv yang dihasilkan. Tapi (!) Semua masalah ini berhasil untuk waktu yang sangat lama. Data selama sebulan, misalnya, dikumpulkan sekitar 45 menit , yang sangat tidak cocok, karena selain laporan rutin, saya ingin membuat analisis untuk tahun berjalan, dan ini akan menjadi waktu yang sangat lama. Tapi "menolak - tawaran." Mereka mulai berpikir.

Jelas, Anda perlu mengoptimalkan kode dan mengaktifkan komputasi paralel. Di PowerShell , kami tidak berhasil dalam lebih dari 5 utas simultan menggunakan alur kerja , dan kami belum "merokok" metode alternatif. Jadi diputuskan untuk mencoba menggeser logika skrip ke R. Utilitas NaviSECCli , yang dapat dijalankan dari bawah R , membuat survei penyimpanan dalam kode sumber, sehingga solusinya cukup cocok.
Dikatakan - beberapa hari - selesai!
Kami memutuskan bahwa pada output saya ingin menerima buletin harian yang berisi jumlah total kesalahan dalam teks surat itu, semacam jadwal untuk jumlah kecelakaan (sehingga ada sesuatu untuk ditunjukkan kepada manajemen), dan juga lampiran dalam bentuk tabel xlsx. Kami menentukan bahwa dalam tabel saya ingin memiliki 3 tab:
- Data kecelakaan selama 3 hari berdasarkan disk dan jenis kecelakaan
- Tab serupa, tetapi selama 30 hari
- Data mentah (jika seseorang ingin menjalankannya di Excel sendiri)
Algoritma skrip
1. Unduh dari csv data yang tersedia di controller;
2. jalankan melalui komputasi paralel siklus untuk semua pengendali dengan mencari catatan pesan alarm yang diperlukan;
3. menggabungkan hasil dalam bingkai data;
4. melakukan pemrosesan dan konversi data;
5. menghasilkan dokumen xlsx;
6. kami membentuk jadwal yang kami simpan di png;
7. membentuk surat yang berisi data yang dikumpulkan;
8. mengirim surat.
Mari kita lihat poin dari algoritma
1. Unduh data yang tersedia di controller dari csv
Format tabel sumber dengan parameter VNX Untuk mengumpulkan informasi darurat, Anda harus terhubung secara seri ke kedua pengontrol ( kolom newA dan newB ) menggunakan perangkat lunak EMC khusus - NaviCLI dengan kunci tertentu.
Untuk kenyamanan, kami memformat ulang tabel yang dihasilkan setelah memuat sehingga alamat IP dari kedua pengontrol berada di kolom yang sama, sehingga Anda dapat membuat satu siklus di seluruh daftar, dan bukan dua yang berturut-turut. Kami melakukan ini menggunakan fungsi kumpulkan . Masalah-masalah bekerja dengan format data "vertikal" atau "horisontal" dengan sangat baik dijelaskan dalam dokumentasi resmi perpustakaan yang rapi . Anda bisa membacanya di sini .
Kami membaca data menggunakan fungsi read_csv2 , kami juga secara manual menentukan jenis kolom melalui parameter col_types tambahan. Ini adalah praktik yang baik, karena sangat mempercepat pemuatan. Dalam kasus kami, ini tidak begitu penting, karena Csv asli berisi kurang dari 100 baris, tetapi kami terbiasa menulis dengan benar.
Pada output, kita mendapatkan bingkai data seperti itu (kolom baru adalah cntName dan cntIP ):
2-3. Kami menjalankan melalui komputasi paralel, siklus untuk semua pengendali dengan mencari catatan pesan alarm yang diperlukan. Gabungkan hasilnya dalam bingkai data
Berikutnya adalah yang paling menarik. Komputasi paralel .
Di R ada beberapa (lebih, bahkan banyak) pilihan untuk komputasi paralel. Saya menyukai tautan dari foreach dan doParallel libraries lebih . Anda dapat membaca tentang mereka dan opsi komputasi paralel lainnya di R di sini .
Singkatnya, kami hanya mengambil 3 langkah :
Langkah 1 Daftarkan kernel zamrud murni CPU untuk bekerja dalam komputasi paralel melalui registerDoParallel (dalam kasus kami, pertama-tama kami mendeteksi jumlah core dalam kasus)
Daftarkan core CPU numCores <- detectCores() registerDoParallel(numCores)
Langkah 2 Kami memulai siklus melalui foreach (jangan lupa untuk menentukan operator % dopar% sehingga siklus berjalan secara paralel dan menunjukkan, melalui parameter .combine, cara kami akan mengumpulkan hasilnya). Dalam kasus kami .combine = rbind , karena pada output setiap loop kita akan memiliki bingkai data .
Kode pengambilan tabel kesalahan Langkah 3 Kami menghapus cluster paralelisme yang dibuat melalui stopImplicitCluster ()
Sedikit lebih detail tentang cara mendapatkan tabel yang dapat dibaca dari teks kesalahan mentah
Dalam bentuk teks, kesalahannya adalah sebagai berikut:
head(errors_raw) [1] "07/13/2019 00:01:46 Bus 0 Enclosure 3 Disk 9(801) Soft SCSI Bus Error [0x00] 841d1080 10006 " [2] "07/13/2019 00:01:46 Bus 0 Enclosure 3 Disk 9(801) Soft SCSI Bus Error [0x00] 841e1a00 10006 " [3] "07/13/2019 00:01:46 Bus 0 Enclosure 3 Disk 9(801) Soft SCSI Bus Error [0x00] 8420b600 10006 " [4] "07/13/2019 00:01:46 Bus 0 Enclosure 3 Disk 9(801) Soft SCSI Bus Error [0x00] 84206900 10006 " [5] "07/13/2019 00:01:46 Bus 0 Enclosure 3 Disk 9(801) Soft SCSI Bus Error [0x00] 841fc900 10006 " [6] "07/13/2019 00:01:46 Bus 0 Enclosure 3 Disk 9(801) Soft SCSI Bus Error [0x00] 841fc000 10006
Di sini kita memiliki nilai yang dipisahkan oleh spasi, yang, pada pandangan pertama, bahkan dalam csv akan dimasukkan secara normal. Tapi itu tidak sesederhana itu. Kompleksitas parsing di sini adalah:
- tanggal dan waktu juga dipisahkan oleh spasi (kejahatan terkecil);
- teks kesalahan terdiri dari "kata-kata", yaitu juga dipisahkan oleh spasi;
- untuk beberapa alasan tidak ada ruang antara nomor disk dan kode kesalahan (yang ada dalam tanda kurung).
Secara umum, surga bagi pecinta ekspresi reguler :)

Saya tidak akan parsing, karena ini masalah selera, tetapi saya akan mengklarifikasi bahwa teks kesalahan harus dipisah-pisahkan, karena nilai-nilai terletak di antara tanda kurung penutup dari nomor kesalahan dan braket kuadrat pembuka dari beberapa nilai lainnya. Dalam satu lingkaran, ini adalah variabel kesalahan .
Ini juga merupakan hal yang menarik bahwa, untuk kenyamanan membentuk kerangka data akhir, kami, ingin mengulang melalui alamat ip pengendali, mengatur urutan tidak melalui kolom dengan alamat ip pengendali (mis. I = VNX_ip $ cntIP ), tetapi melalui nomor baris (mis. e. i = 1: nrow (VNX_ip) ). Ini memungkinkan kami, saat membentuk bingkai data dengan kesalahan yang sudah diuraikan, untuk menambahkan nomor cluster dan nama penyimpanan melalui panggilan VNX_ip $ cl [i] dan VNX_ip $ Name [i] . Tanpa ini, gabungan harus dibuat, yang akan lebih lambat dan lebih buruk dibaca dalam kode.
Pada akhirnya, kita mendapatkan kerangka data (jujur, lalu tibble , tetapi perbedaannya berada di luar cakupan artikel), yang berisi semua data yang kita butuhkan. Yaitu pada sistem penyimpanan mana, pada disk mana, ketika kesalahan apa yang terjadi.
Tampilan akhir Bingkai data Hal yang paling cerdas adalah bahwa seluruh siklus pemungutan suara paralel semua sistem penyimpanan tidak memakan waktu 30 menit, tetapi 30 detik .
Alhamdulillah ini tidak terjadi ketika 30 detik terlalu cepat.

Perlu diperjelas bahwa kode PowerShell juga mengumpulkan nomor seri disk dari semua sistem penyimpanan dalam satu siklus, dan pada saat menulis ulang kode pada R, data ini berlebihan. Jadi perbandingan runtime tidak sepenuhnya jujur, tetapi masih mengesankan.
Konversi data untuk dokumen xlsx dikurangi menjadi memfilter tabel sumber pada 3 hari terakhir, serta pada bulan lalu dan mengonversi kolom dengan nama kesalahan ke format "horizontal", sehingga setiap jenis kesalahan berada di kolom yang terpisah. Fungsi terpisah ditulis untuk ini (agar tidak menduplikasi langkah yang sama 2 kali)
Fungsi Penyaringan Sumber myErrorStats <- function(data, period, orderColname = quo(Soft_Media_Error)) { data %>% filter(Date > period) %>% group_by(cl, Storage, Disk, Error) %>% summarise(count = n()) %>% spread(Error, count, fill = 0) %>% arrange(desc(!!orderColname)) }
Untuk menampilkan jenis kesalahan dalam kolom terpisah, fungsi sebaran diterapkan dengan kunci tambahan isian = 0 , dengan mana nilai yang hilang diisi dengan 0 . Tanpa kunci ini, jika pada suatu hari tidak ada beberapa jenis kesalahan, kolom yang sesuai akan memiliki nilai NA .
Juga, dalam fungsi ini, saya ingin menjaga kemampuan untuk meneruskan nama kolom untuk pengurutan sebagai variabel, tetapi pada saat yang sama memiliki nilai default untuk variabel ini. Untuk ini, sintaks khusus dplyr digunakan , yang dapat Anda baca lebih lanjut di sini .
Dalam kasus kami, ketika mendefinisikan parameter suatu fungsi, kami menetapkan salah satunya ke nilai default dan mengutipnya ( orderColname = quo (Soft_Media_Error) ), dan kemudian, ketika dipanggil, letakkan karakter di depannya !! untuk mengatur (desc (!! orderColname))) .
Penampilan tabel dengan kesalahan untuk bulan itu Saya menganalisis pembentukan dokumen xlsx dalam artikel tentang laporan kondisi VM , jadi saya tidak akan membahas secara terperinci. Semua kode diberikan di akhir artikel.

Berikut adalah fitur penting yang meningkatkan keterbacaan laporan:
- Tab yang ditandatangani (secara default yang paling menarik adalah terbuka);
- Nama kolom yang disorot
- Autoformatting semua kolom sehingga semua teks dapat dibaca tanpa harus memperluas kolom.
Pada grafik, saya ingin mendapatkan jumlah kesalahan per hari untuk semua sistem penyimpanan menurut jenis. Sebagai alat menggambar, diputuskan untuk menggunakan pustaka ggplot2 standar.
Versi pertama grafik menunjukkan semua kesalahan pada satu grafik dan terlihat seperti ini:

Kolega mengatakan bahwa itu ternyata tidak dapat dibaca.
Apa yang akan mereka pahami? !!!!
Komentar itu diperhitungkan dan fungsi facet_grid ditambahkan ke kolom standar ( geom_bar ) untuk membagi hasilnya menjadi grafik yang terpisah berdasarkan jenis kesalahan.
Hasil akhir cocok untuk semua orang.

Persiapan data, grafik, menyimpan ke file Dari yang menarik dalam susunan jadwal.
Saya ingin grafik berada dalam urutan tertentu. Untuk melakukan ini, parameter pembentukan baris di facet_grid harus ditransfer sebagai faktor, atau lebih tepatnya faktor yang dipesan . Faktor adalah suatu format data yang licik dalam R, yang merupakan sekumpulan nilai (dalam kasus kami, string, mis. Karakter ), dan sekumpulan nilai-nilai ini didefinisikan secara ketat (disebut level faktor), dan bahkan level ini diurutkan. Kedengarannya rumit, tetapi semuanya jatuh ke tempatnya jika Anda mengatakan bahwa nama-nama bulan adalah contoh yang bagus dari faktor yang dipesan. Yaitu kita tahu nama apa yang bisa dimiliki bulan, dan kita juga tahu (well, saya harap) yang pertama kali datang Januari, lalu Februari, lalu Maret, dll Itu pada prinsip yang sama bahwa kita menciptakan faktor.
Pembentukan dan pengiriman surat, serta pembentukan tugas di Windows scheduller juga dipertimbangkan dalam artikel tentang laporan kondisi VM . Kami cukup menaruh beberapa variabel ke dalam teks dan memformatnya lebih atau kurang dengan jelas. Jangan lupakan keterikatannya.
Bentuk akhir dari surat itu Kesimpulan
R sekali lagi terbukti menjadi alat universal untuk melakukan tugas sehari-hari dan memvisualisasikan hasil mereka. Dan dengan komputasi paralel yang diaktifkan, alat ini juga menjadi cepat.
Praktek juga menunjukkan bahwa PowerShell sangat lambat dalam mem-parsing log dan menerjemahkannya ke dalam format yang dapat dibaca.
Terima kasih banyak untuk semua orang yang membaca begitu banyak surat sampai akhir.
Kode aplikasi lengkap
- : EMC VNX 5300
- : NaviCLI-Win-32-x86-en_US-7.31.25.1.29-1
- , : 4*2 CPU, 8 Gb RAM
R > sessionInfo() R version 3.5.3 (2019-03-11) Platform: x86_64-w64-mingw32/x64 (64-bit) Running under: Windows Server 2012 R2 x64 (build 9600) Matrix products: default locale: [1] LC_COLLATE=Russian_Russia.1251 LC_CTYPE=Russian_Russia.1251 LC_MONETARY=Russian_Russia.1251 [4] LC_NUMERIC=C LC_TIME=Russian_Russia.1251 attached base packages: [1] parallel stats graphics grDevices utils datasets methods base other attached packages: [1] taskscheduleR_1.4 pander_0.6.3 doParallel_1.0.14 iterators_1.0.10 foreach_1.4.4 mailR_0.4.1 [7] xlsx_0.6.1 stringi_1.4.3 zoo_1.8-6 lubridate_1.7.4 wesanderson_0.3.6 forcats_0.4.0 [13] stringr_1.4.0 dplyr_0.8.3 purrr_0.3.2 readr_1.3.1 tidyr_0.8.3 tibble_2.1.3 [19] ggplot2_3.2.0 tidyverse_1.2.1 loaded via a namespace (and not attached): [1] tidyselect_0.2.5 reshape2_1.4.3 rJava_0.9-11 haven_2.1.1 lattice_0.20-38 colorspace_1.4-1 [7] vctrs_0.2.0 generics_0.0.2 utf8_1.1.4 rlang_0.4.0 R.oo_1.22.0 pillar_1.4.2 [13] glue_1.3.1 withr_2.1.2 R.utils_2.9.0 RColorBrewer_1.1-2 modelr_0.1.4 readxl_1.3.1 [19] plyr_1.8.4 munsell_0.5.0 gtable_0.3.0 cellranger_1.1.0 rvest_0.3.4 R.methodsS3_1.7.1 [25] codetools_0.2-16 labeling_0.3 fansi_0.4.0 xlsxjars_0.6.1 broom_0.5.2 Rcpp_1.0.1 [31] scales_1.0.0 backports_1.1.4 jsonlite_1.6 digest_0.6.20 hms_0.5.0 grid_3.5.3 [37] cli_1.1.0 tools_3.5.3 magrittr_1.5 lazyeval_0.2.2 crayon_1.3.4 pkgconfig_2.0.2 [43] zeallot_0.1.0 data.table_1.12.2 xml2_1.2.0 assertthat_0.2.1 httr_1.4.0 rstudioapi_0.10 [49] R6_2.4.0 nlme_3.1-137 compiler_3.5.3