R болон PowerShell ашиглан виртуал машинуудын эрүүл мэндийн талаар өдөр бүр мэдээлдэг

R болон PowerShell ашиглан виртуал машинуудын эрүүл мэндийн талаар өдөр бүр мэдээлдэг

нэвтрэх

Өдрийн мэнд. Хагас жилийн турш бид виртуал машинуудын (зөвхөн биш) байдлын талаар тайлан гаргадаг скрипт (эсвэл скриптүүдийн багц) ажиллуулж байна. Би өөрийн бүтээлийн туршлага болон кодыг хуваалцахаар шийдсэн. Би шүүмжлэл хүлээж, энэ материал нь хэн нэгэнд хэрэгтэй байж магадгүй гэж найдаж байна.

Хэрэгцээ үүсгэх

Бидэнд маш олон виртуал машин байдаг (1500 vCenters-д тараагдсан 3 орчим VM). Шинээр бий болж, хуучин нь нэлээд олон удаа устдаг. Эмх цэгцтэй байлгахын тулд vCenter-д хэд хэдэн тусгай талбаруудыг нэмж, VM-үүдийг дэд системд хуваах, тэдгээр нь туршилтынх эсэх, хэн, хэзээ үүсгэсэн зэргийг зааж өгсөн. Хүний хүчин зүйлээс болж машинуудын талаас илүү хувь нь хоосон талбайтай үлдсэн нь ажлыг хүндрүүлжээ. Зургаан сар тутамд нэг удаа хэн нэгэн сандарч, энэ өгөгдлийг шинэчлэхээр ажиллаж эхэлсэн боловч долоо хоног хагасын дараа үр дүн нь хамааралгүй болсон.
Машин бүтээх програмууд, тэдгээрийг бий болгох үйл явц гэх мэт байх ёстой гэдгийг хүн бүр ойлгодог гэдгийг нэн даруй тодруулъя. гэх мэт. Үүний зэрэгцээ хүн бүр энэ үйл явцыг хатуу дагаж мөрддөг бөгөөд бүх зүйл эмх цэгцтэй байдаг. Харамсалтай нь энд тийм биш, гэхдээ энэ нь нийтлэлийн сэдэв биш юм :)

Ерөнхийдөө талбаруудыг зөв бөглөх эсэхийг шалгах ажлыг автоматжуулахаар шийдсэн.
Бүх хариуцлагатай инженерүүд болон дарга нартаа буруу бөглөсөн машинуудын жагсаалт бүхий өдөр бүр захидал илгээх нь сайн эхлэл болно гэж бид шийдсэн.

Энэ үед миний хамтран ажиллагсад PowerShell-д аль хэдийн скрипт хэрэгжүүлсэн байсан бөгөөд энэ нь өдөр бүр хуваарийн дагуу бүх vCenter-ийн бүх машинууд дээр мэдээлэл цуглуулж, 3 csv баримт бичгийг (тус бүр өөрийн vCenter-д зориулж) үүсгэдэг. нийтлэг диск. Энэ скриптийг үндэс болгон авч, бидэнд тодорхой туршлага хуримтлуулсан R хэлийг ашиглан чекүүдээр нэмэхээр шийдсэн.

Эцсийн боловсруулалтын явцад уг шийдэл нь шуудангаар мэдээлэл, үндсэн болон түүхэн хүснэгт бүхий мэдээллийн бааз (энэ талаар дараа нь), мөн vm-ийн жинхэнэ бүтээгчид болон тэдгээрийг үүсгэсэн цаг хугацааг олохын тулд vSphere бүртгэлд дүн шинжилгээ хийсэн.

Хөгжүүлэхдээ IDE RStudio Desktop болон PowerShell ISE ашигласан.

Скриптийг ердийн Windows виртуал машинаас эхлүүлсэн.

Ерөнхий логикийн тодорхойлолт.

Скриптүүдийн ерөнхий логик нь дараах байдалтай байна.

  • Бид R-ээр дамжуулан дууддаг PowerShell скриптийг ашиглан виртуал машин дээрх өгөгдлийг цуглуулж, үр дүнг нэг csv болгон нэгтгэдэг. Хэл хоорондын урвуу харилцан үйлчлэл ижил төстэй байдлаар хийгддэг. (Өгөгдлийг R-ээс PowerShell руу хувьсагчийн хэлбэрээр шууд дамжуулах боломжтой байсан ч энэ нь хэцүү бөгөөд завсрын csv-тэй байх нь дибаг хийх, завсрын үр дүнг хэн нэгэнтэй хуваалцахад хялбар болгодог).
  • R ашиглан бид утгыг нь шалгаж байгаа талбарт хүчинтэй параметрүүдийг үүсгэдэг. - Бид мэдээллийн захидалд оруулах эдгээр талбаруудын утгыг агуулсан word баримт бичгийг бүтээж байгаа бөгөөд энэ нь хамт ажиллагсдынхаа "Үгүй, гэхдээ би үүнийг яаж бөглөх ёстой вэ?" Гэсэн асуултын хариулт болно.
  • Бид R ашиглан csv-ээс бүх VM-ийн өгөгдлийг ачаалж, өгөгдлийн фрейм үүсгэж, шаардлагагүй талбаруудыг устгаж, бүх VM-ийн хураангуй мэдээллийг агуулсан мэдээллийн xlsx баримт бичгийг үүсгэн хуваалцсан нөөцөд байршуулдаг.
  • Бид бүх VM-ийн өгөгдлийн фреймд талбаруудыг бөглөх зөв эсэхийг шалгах бүх шалгалтыг хийж, зөвхөн буруу бөглөсөн талбартай (зөвхөн эдгээр талбарууд) VM-уудыг агуулсан хүснэгтийг үүсгэдэг.
  • Бид VM-ийн жагсаалтыг өөр PowerShell скрипт рүү илгээдэг бөгөөд энэ нь VM үүсгэх үйл явдлын vCenter бүртгэлийг үзэх бөгөөд энэ нь VM-ийг үүсгэх тооцоолсон хугацаа болон төлөвлөсөн бүтээгчийг зааж өгөх боломжийг олгоно. Энэ нь хэнийх нь машин болохыг хэн ч хүлээн зөвшөөрөхгүй байгаа тохиолдолд зориулагдсан юм. Энэ скрипт хурдан ажиллахгүй, ялангуяа маш олон лог байгаа бол бид зөвхөн сүүлийн 2 долоо хоногийг үзэхээс гадна хэд хэдэн VM дээр мэдээлэл хайх боломжийг олгодог ажлын урсгалыг ашигладаг. Жишээ скрипт нь энэ механизмын талаархи дэлгэрэнгүй тайлбарыг агуулдаг. Бид үр дүнг csv-д нэмж, R-д дахин ачаална.
  • Бид гоёмсог форматтай xlsx баримт бичгийг үүсгэдэг бөгөөд үүнд буруу бөглөсөн талбаруудыг улаан өнгөөр ​​тодруулж, зарим баганад шүүлтүүрийг хэрэглэж, төлөвлөсөн бүтээгчид болон VM-ийг үүсгэсэн цагийг агуулсан нэмэлт багануудыг зааж өгөх болно.
  • Бид имэйл илгээдэг бөгөөд үүнд хүчинтэй талбарын утгыг тодорхойлсон баримт бичиг, мөн талбаруудыг буруу бөглөсөн хүснэгтийг хавсаргадаг. Текстэнд бид буруу үүсгэсэн VM-ийн нийт тоо, хуваалцсан эх сурвалжийн холбоос, урам зоригтой зургийг зааж өгсөн болно. Хэрэв буруу бөглөсөн VM байхгүй бол бид илүү аз жаргалтай урам зоригтой зураг бүхий өөр захидал илгээдэг.
  • Бид түүхэн хүснэгтүүдийн хэрэгжүүлсэн механизмыг харгалзан SQL Server мэдээллийн сан дахь бүх VM-ийн өгөгдлийг бүртгэдэг (маш сонирхолтой механизм - дараа нь)

Үнэндээ скриптүүд

Үндсэн R кодын файл

# Путь к рабочей директории (нужно для корректной работы через виндовый планировщик заданий)
setwd("C:ScriptsgetVm")
#### Подгружаем необходимые пакеты ####
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.ruVM', 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.ruVM', 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")

PowerShell дээр vm-ийн жагсаалтыг авах скрипт

# Данные для подключения и другие переменные
$vCenterNames = @(
"vcenter01", 
"vcenter02", 
"vcenter03"
)
$vCenterUsername = "myusername"
$vCenterPassword = "mypassword"
$filename = "C:ScriptsgetVmdataallvmall-vm-$(get-date -f yyyy-MM-dd).csv"
$destinationSMB = "server.rumyfolder$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
}

Виртуал машин бүтээгчид болон тэдгээрийг үүсгэсэн огноог бүртгэлээс гаргаж авдаг PowerShell скрипт.

# Путь к файлу, из которого будем доставать список VM
$VMfilePath = "C:ScriptsgetVmcreators_VMcreators_VM_$(get-date -f yyyy-MM-dd).csv"
# Путь к файлу, в который будем записывать результат
$filePath = "C:ScriptsgetVmdatacreatorscreators-$(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"

Номын сан нь онцгой анхаарал хандуулах ёстой xlsx, энэ нь зөвхөн CSV хүснэгт биш, захидлын хавсралтыг тодорхой форматтай (удирдлагын хүссэнээр) хийх боломжтой болгосон.

Буруу бөглөсөн машинуудын жагсаалт бүхий сайхан xlsx баримтыг үүсгэж байна

# Создаём новую книгу
# Возможные значения : "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)

Гаралт нь иймэрхүү харагдаж байна:

R болон PowerShell ашиглан виртуал машинуудын эрүүл мэндийн талаар өдөр бүр мэдээлдэг

Windows хуваарь тохируулагчийг тохируулах талаар сонирхолтой нюанс бас байсан. Бүх зүйл байх ёстойгоор эхлэхийн тулд зөв эрх, тохиргоог олох боломжгүй байв. Үүний үр дүнд R номын сан олдсон бөгөөд энэ нь өөрөө R скриптийг эхлүүлэх даалгаврыг бий болгодог бөгөөд бүртгэлийн файлыг ч мартдаггүй. Дараа нь та даалгаврыг гараар засаж болно.

Windows Scheduler-д даалгавар үүсгэдэг хоёр жишээ бүхий R кодын хэсэг

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)

Мэдээллийн сангийн талаар тусад нь

Скриптийг тохируулсны дараа бусад асуудлууд гарч ирэв. Жишээлбэл, би VM-г устгасан огноог олохыг хүссэн боловч vCenter дахь бүртгэлүүд аль хэдийн элэгдсэн байв. Скрипт нь өдөр бүр файлуудыг хавтсанд хийдэг бөгөөд үүнийг цэвэрлэдэггүй (бид санаж байхдаа гараар цэвэрлэдэг) тул та хуучин файлуудыг үзэж, энэ VM байхгүй анхны файлыг олох боломжтой. Гэхдээ энэ нь тийм ч сайхан биш юм.

Би түүхэн мэдээллийн сан үүсгэхийг хүссэн.

MS SQL SERVER-ийн функциональ байдал - системийн хувилбартай түр зуурын хүснэгт аврах ажилд ирэв. Энэ нь ихэвчлэн түр зуурын (түр бус) хүснэгт гэж орчуулагддаг.

Та эндээс дэлгэрэнгүй уншиж болно Microsoft-ын албан ёсны баримт бичиг.

Товчхондоо, бид хүснэгт үүсгэж, үүнийг хувилбартай болгоно гэж хэлэх ба SQL сервер нь энэ хүснэгтэд нэмэлт 2 огнооны багана (бичлэг үүсгэгдсэн огноо ба бичлэгийн дуусах огноо) болон өөрчлөгдөх нэмэлт хүснэгт үүсгэдэг. бичигдэх болно. Үүний үр дүнд бид хамгийн сүүлийн үеийн мэдээллийг хүлээн авч, жишээ нь баримт бичигт өгөгдсөн энгийн асуултуудын тусламжтайгаар бид тодорхой виртуал машины амьдралын мөчлөг эсвэл тодорхой цэг дэх бүх VM-ийн төлөвийг харж болно. цагтаа.

Гүйцэтгэлийн үүднээс авч үзвэл түр хүснэгтэд бичих гүйлгээ дуусах хүртэл үндсэн хүснэгт рүү бичих гүйлгээ дуусахгүй. Тэдгээр. Олон тооны бичих үйлдэлтэй хүснэгтүүд дээр энэ функцийг болгоомжтой хийх хэрэгтэй, гэхдээ бидний хувьд энэ нь үнэхээр гайхалтай зүйл юм.

Механизмыг зөв ажиллуулахын тулд би шинэ хүснэгтийг бүх VM-ийн өгөгдөлтэй өгөгдлийн санд хадгалагдсантай харьцуулж, зөвхөн өөрчилсөн мөрүүдийг бичих жижиг кодыг R дээр нэмэх шаардлагатай болсон. Код нь тийм ч ухаалаг биш, энэ нь compareDF номын санг ашигладаг, гэхдээ би үүнийг доор танилцуулах болно.

Өгөгдлийн санд өгөгдөл бичих R код

# Подцепляем пакеты
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)

Нийт

Скриптийг хэрэгжүүлсний үр дүнд хэдхэн сарын дотор дэг журмыг сэргээж, хадгалсан. Заримдаа буруу бөглөсөн VM гарч ирдэг ч скрипт нь сайн сануулагч болж, ховор VM нь 2 өдөр дараалан жагсаалтад ордог.

Түүхэн мэдээлэлд дүн шинжилгээ хийх үндэслэлийг мөн хийсэн.

Үүний ихэнхийг өвдөг дээрээ биш, харин тусгай програм хангамжийн тусламжтайгаар хэрэгжүүлж болох нь ойлгомжтой боловч даалгавар нь сонирхолтой бөгөөд сонголттой байсан гэж хэлж болно.

R нь статистикийн асуудлыг шийдвэрлэхэд тохиромжтой төдийгүй бусад мэдээллийн эх сурвалжуудын хооронд маш сайн "давхарга" болж чаддаг маш сайн бүх нийтийн хэл гэдгээ дахин харуулсан.

R болон PowerShell ашиглан виртуал машинуудын эрүүл мэндийн талаар өдөр бүр мэдээлдэг

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх