Tuarascálacha laethúla ar shláinte meaisíní fíorúla a úsáideann R agus PowerShell

Tuarascálacha laethúla ar shláinte meaisíní fíorúla a úsáideann R agus PowerShell

Iontráil

Tráthnóna maith. Le leathbhliain anois táimid ag rith script (nó in áit sraith scripteanna) a ghineann tuairiscí ar stádas na meaisíní fíorúla (agus ní amháin). Chinn mé mo thaithí cruthú agus an cód féin a roinnt. Tá súil agam le cáineadh agus go bhféadfadh an t-ábhar seo a bheith úsáideach do dhuine éigin.

Foirmiú riachtanas

Tá go leor meaisíní fíorúla againn (thart ar 1500 VM atá scaipthe ar fud 3 vCenter). Cruthaítear cinn nua agus scriostar seanchinn go minic. Chun ord a choinneáil, cuireadh roinnt réimsí saincheaptha le vCenter chun VManna a roinnt ina Fhochórais, a chur in iúl cé acu cinn tástála iad, agus cé a chruthaigh agus cathain a cruthaíodh iad. Mar thoradh ar an bhfachtóir daonna gur fágadh níos mó ná leath de na meaisíní le réimsí bána, rud a chuir casta ar an obair. Uair amháin gach sé mhí, chuaigh duine éigin anchúinse amach agus thosaigh sé ag obair ar na sonraí seo a nuashonrú, ach níor bhain an toradh as a bheith ábhartha tar éis seachtain go leith.
Lig dom a shoiléiriú láithreach go dtuigeann gach duine go gcaithfidh iarratais a bheith ann chun meaisíní a chruthú, próiseas chun iad a chruthú, etc. agus mar sin de. Agus ag an am céanna, leanann gach duine an próiseas seo go docht agus tá gach rud in ord. Ar an drochuair, ní hé seo an cás anseo, ach ní hé seo ábhar an ailt :)

Go ginearálta, rinneadh an cinneadh seiceáil uathoibrithe a dhéanamh ar cheart líonadh na réimsí.
Shocraigh muid go gcuirfí tús maith le litir laethúil le liosta de na meaisíní a líonadh amach go mícheart chuig gach innealtóir freagrach agus a gceannairí.

Ag an bpointe seo, bhí script curtha i bhfeidhm cheana féin ag duine de mo chomhghleacaithe i PowerShell, a bhailigh gach lá, de réir sceidil, faisnéis ar gach meaisín de gach vCenters agus ghin sé 3 dhoiciméad csv (gach ceann dá vCenter féin), a uaslódáil chuig diosca coitianta. Socraíodh an script seo a ghlacadh mar bhonn agus é a fhorlíonadh le seiceálacha ag baint úsáide as an teanga R, a raibh roinnt taithí againn léi.

Sa phróiseas críochnaithe, fuair an réiteach faisnéis tríd an bpost, bunachar sonraí le príomhthábla agus tábla stairiúil (níos mó ar seo níos déanaí), chomh maith le hanailís ar logaí vSphere chun cruthaitheoirí iarbhír vm a aimsiú agus am a gcruthú.

Úsáideadh IDE RStudio Desktop agus PowerShell ISE le haghaidh forbartha.

Seoltar an script ó mheaisín fíorúil Windows rialta.

Cur síos ar an loighic ghinearálta.

Seo a leanas loighic ghinearálta na scripteanna.

  • Bailímid sonraí ar mheaisíní fíorúla ag baint úsáide as script PowerShell, a dtugaimid trí R, agus comhcheanglaímid an toradh i csv amháin. Déantar an idirghníomhaíocht droim ar ais idir teangacha mar an gcéanna. (bhí in ann sonraí a thiomáint go díreach ó R go PowerShell i bhfoirm athróg, ach tá sé seo deacair, agus má tá csvs idirmheánacha ann bíonn sé níos éasca torthaí idirmheánacha a dhífhabhtú agus a roinnt le duine éigin).
  • Ag baint úsáide as R, foirmímid paraiméadair bhailí do na réimsí a bhfuil a luachanna á seiceáil againn. — Táimid ag cruthú doiciméad Word ina mbeidh luachanna na réimsí seo le cur isteach sa litir faisnéise, a bheidh mar fhreagra ar cheisteanna comhghleacaithe “Ní hea, ach conas ba cheart dom é seo a líonadh amach?”
  • Lódáilimid sonraí do gach VM ó csv ag baint úsáide as R, cruthaímid fráma sonraí, bainimid réimsí neamhriachtanacha agus cruthaímid doiciméad xlsx faisnéise ina mbeidh faisnéis achomair do gach VM, a uaslódaimid chuig acmhainn chomhroinnte.
  • Cuirimid gach seiceáil i bhfeidhm maidir le cruinneas líonadh na réimsí ar an bhfráma sonraí do gach VM agus cruthaímid tábla nach bhfuil ann ach VManna a bhfuil réimsí líonta go mícheart (agus na réimsí seo amháin).
  • Seolaimid an liosta VM mar thoradh air chuig script PowerShell eile, a bhreathnóidh ar na logaí vCenter le haghaidh imeachtaí cruthaithe VM, a ligfidh dúinn am measta cruthú an VM agus an cruthaitheoir beartaithe a chur in iúl. Is amhlaidh an cás nuair nach n-admhaíonn aon duine cé acu carr atá ann. Ní oibríonn an script seo go tapa, go háirithe má tá go leor logs ann, mar sin ní fhéachaimid ach ar na 2 sheachtain anuas, agus úsáidimid sreabhadh oibre freisin a ligeann duit faisnéis a chuardach ar roinnt VM ag an am céanna. Tá tráchtanna mionsonraithe sa script shamplach ar an meicníocht seo. Cuirimid an toradh isteach i csv, a luchtaimid arís isteach i R.
  • Gineann muid doiciméad xlsx atá formáidithe go hálainn ina ndíreofar aird ar réimsí atá líonta go mícheart i dearg, cuirfear scagairí i bhfeidhm ar roinnt colúin, agus léireofar colúin bhreise ina bhfuil na cruthaitheoirí beartaithe agus am cruthaithe an VM.
  • Gineann muid ríomhphost, ina gcuirimid doiciméad i gceangal a chuireann síos ar na luachanna réimse bailí, chomh maith le tábla ina bhfuil réimsí líonta go mícheart. Sa téacs léirímid líon iomlán na VManna a cruthaíodh go mícheart, nasc chuig acmhainn roinnte agus pictiúr spreagtha. Mura bhfuil aon VManna líonta go mícheart, seolaimid litir eile le pictiúr inspreagtha níos sona.
  • Déanaimid taifead ar shonraí do gach VM i mbunachar sonraí Freastalaí SQL, ag cur san áireamh meicníocht forfheidhmithe na dtáblaí stairiúla (meicníocht an-suimiúil - faoi cé acu níos déanaí)

I ndáiríre scripteanna

Príomhchomhad cód 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")

Script chun liosta vm a fháil i PowerShell

# Данные для подключения и другие переменные
$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
}

Script PowerShell a bhaintear as na logaí cruthaitheoirí meaisíní fíorúla agus dáta a gcruthú

# Путь к файлу, из которого будем доставать список 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"

Tá aird ar leith tuillte ag an leabharlann XLSX, rud a d'fhág gur féidir an ceangaltán leis an litir a fhormáidiú go soiléir (mar is maith leis an mbainistíocht), agus ní tábla CSV amháin.

Cáipéis álainn xlsx a ghiniúint le liosta de na meaisíní a líonadh isteach go mícheart

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

Breathnaíonn an t-aschur rud éigin mar seo:

Tuarascálacha laethúla ar shláinte meaisíní fíorúla a úsáideann R agus PowerShell

Bhí nuance suimiúil ann freisin maidir le sceidealóir Windows a bhunú. Níorbh fhéidir na cearta agus na socruithe cearta a aimsiú ionas go dtosódh gach rud mar ba chóir. Mar thoradh air sin, fuarthas an leabharlann R, rud a chruthaíonn tasc féin chun script R a sheoladh agus ní fiú dearmad a dhéanamh ar an gcomhad logála. Ansin is féidir leat an tasc a cheartú de láimh.

Píosa de chód R le dhá shampla a chruthaíonn tasc sa Sceidealóir 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)

Ar leithligh faoin mbunachar sonraí

Tar éis an script a shocrú, thosaigh saincheisteanna eile ag teacht chun cinn. Mar shampla, bhí mé ag iarraidh an dáta a aimsiú nuair a scriosadh an VM, ach bhí na logaí i vCenter caite cheana féin. Ós rud é go gcuireann an script comhaid i bhfillteán gach lá agus nach ndéanann sé é a ghlanadh (glanaimid é lenár lámha nuair a chuimhnímid), is féidir leat breathnú trí sheanchomhaid agus an chéad chomhad a aimsiú nach bhfuil an VM seo i láthair. Ach níl sé sin fionnuar.

Bhí mé ag iarraidh bunachar sonraí stairiúil a chruthú.

Tháinig feidhmiúlacht MS SQL SERVER - tábla ama leagan córais - chun tarrthála. De ghnáth aistrítear é mar tháblaí sealadacha (ní sealadach).

Is féidir leat léamh go mion ag Doiciméadúchán oifigiúil Microsoft saor in aisce,.

I mbeagán focal, cruthaímid tábla, abair go mbeidh sé againn le leagan, agus cruthaíonn Freastalaí SQL 2 cholún dáta ama breise sa tábla seo (an dáta a cruthaíodh an taifead agus dáta éaga an taifid) agus tábla breise ina n-athraíonn scríobhfar. Mar thoradh air sin, faighimid faisnéis cothrom le dáta agus, trí fhiosrúcháin shimplí, a bhfuil samplaí díobh tugtha sa doiciméadú, is féidir linn saolré meaisín fíorúil ar leith a fheiceáil, nó staid gach VM ag pointe áirithe. in am.

Ó thaobh feidhmíochta de, ní chríochnóidh an t-idirbheart scríobh chuig an bpríomhthábla go dtí go gcríochnóidh an t-idirbheart scríobh chuig an tábla sealadach. Iad siúd. ar tháblaí le líon mór oibríochtaí scríbhneoireachta, ba cheart an fheidhmiúlacht seo a chur i bhfeidhm go cúramach, ach is rud iontach é inár gcás.

Le go n-oibreodh an mheicníocht i gceart, bhí orm píosa beag cód a chur leis in R a chuirfeadh an tábla nua i gcomparáid le sonraí do gach VM leis an gceann atá stóráilte sa bhunachar sonraí agus gan ach sraitheanna athraithe a scríobh chuige. Níl an cód go háirithe cliste; úsáideann sé an leabharlann compareDF, ach cuirfidh mé i láthair é thíos freisin.

R cód chun sonraí a scríobh chuig bunachar sonraí

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

Ar an iomlán

Mar thoradh ar chur i bhfeidhm na scripte, rinneadh an t-ordú a athchóiriú agus a chothabháil laistigh de chúpla mí. Uaireanta tagann VManna líonta go mícheart le feiceáil, ach feidhmíonn an script mar mheabhrúchán maith agus críochnaíonn VM annamh ar an liosta ar feadh 2 lá as a chéile.

Rinneadh obair talún freisin chun anailís a dhéanamh ar shonraí stairiúla.

Tá sé soiléir gur féidir go leor de seo a chur i bhfeidhm ní ar na glúine, ach le bogearraí speisialaithe, ach bhí an tasc suimiúil agus, d'fhéadfadh duine a rá, roghnach.

Arís eile léirigh R gur teanga uilíoch den scoth í, atá foirfe ní hamháin chun fadhbanna staitistiúla a réiteach, ach a fheidhmíonn freisin mar “chiseal” den scoth idir foinsí sonraí eile.

Tuarascálacha laethúla ar shláinte meaisíní fíorúla a úsáideann R agus PowerShell

Foinse: will.com

Add a comment