د R او PowerShell په کارولو سره د مجازی ماشینونو روغتیا په اړه ورځني راپورونه

د R او PowerShell په کارولو سره د مجازی ماشینونو روغتیا په اړه ورځني راپورونه

د ننوتلو

بعد له غرمه مو پخیر. د نیم کال لپاره اوس موږ یو سکریپټ چلوو (یا بلکه د سکریپټونو سیټ) چې د مجازی ماشینونو حالت په اړه راپورونه رامینځته کوي (او نه یوازې). ما پریکړه وکړه چې زما د جوړولو تجربه او کوډ پخپله شریک کړم. زه د انتقاد لپاره امید لرم او دا چې دا مواد ممکن د یو چا لپاره ګټور وي.

د اړتیا جوړښت

موږ ډیری مجازی ماشینونه لرو (شاوخوا 1500 VMs په 3 vCenters کې ویشل شوي). نوي جوړ شوي او زاړه ډیری وختونه حذف کیږي. د نظم ساتلو لپاره، څو ګمرکي ساحې vCenter ته اضافه شوي ترڅو VMs په فرعي سیسټمونو ویشل شي، دا په ګوته کړي چې ایا دوی ازموینې دي، او د چا لخوا او کله رامینځته شوي. بشري فکتور د دې حقیقت لامل شو چې له نیمایي څخه ډیر ماشینونه د خالي ساحو سره پاتې شوي، چې کار یې پیچلی کړی. په هرو شپږو میاشتو کې یو ځل، یو څوک ویریدل او د دې معلوماتو د تازه کولو لپاره یې کار پیل کړ، مګر پایله یې د یوې نیمې اونۍ وروسته پای ته ورسیده.
اجازه راکړئ سمدلاسه روښانه کړم چې هرڅوک پوهیږي چې د ماشینونو رامینځته کولو لپاره غوښتنلیکونه شتون لري ، د دوی رامینځته کولو پروسه او داسې نور. او همداسی پسی. او په ورته وخت کې، هرڅوک دا پروسه په کلکه تعقیبوي او هرڅه په ترتیب کې دي. له بده مرغه، دلته قضیه نه ده، مګر دا د مقالې موضوع نه ده :)

په عموم کې، پریکړه وشوه چې په ساحو کې د ډکولو درستیت چک کول اتومات کړي.
موږ پریکړه وکړه چې د غلط ډک شوي ماشینونو لیست سره یو ورځنی لیک ټولو مسؤل انجینرانو او د دوی بادارانو ته یو ښه پیل وي.

په دې وخت کې، زما یو همکار لا دمخه په PowerShell کې یو سکریپټ پلي کړی و، چې هره ورځ، د مهال ویش سره سم، د ټولو vCenters په ټولو ماشینونو کې معلومات راټولوي او د 3 csv سندونه (هر یو د خپل vCenter لپاره) تولیدوي، کوم چې پورته شوي. یو عام ډیسک. دا پریکړه وشوه چې دا سکریپټ د اساس په توګه واخلو او د R ژبې په کارولو سره د چکونو سره ضمیمه کړو، چې موږ ورسره یو څه تجربه درلوده.

د نهایی کولو په پروسه کې ، حل د بریښنالیک له لارې معلومات ترلاسه کړل ، یو ډیټابیس د اصلي او تاریخي میز سره (په دې اړه نور وروسته وروسته) ، او همدارنګه د vSphere لاګونو تحلیل ترڅو د vm اصلي جوړونکي او د دوی د رامینځته کیدو وخت ومومي.

IDE RStudio ډیسټاپ او PowerShell ISE د پراختیا لپاره کارول شوي.

سکریپټ د منظم وینډوز مجازی ماشین څخه پیل شوی.

د عمومي منطق توضیحات.

د سکریپټ عمومي منطق په لاندې ډول دی.

  • موږ د PowerShell سکریپټ په کارولو سره په مجازی ماشینونو کې ډاټا راټولوو، کوم چې موږ د R له لارې غږ کوو، او پایله یې په یو csv کې یوځای کوو. د ژبو ترمنځ متقابل تعامل په ورته ډول ترسره کیږي. (دا ممکنه وه چې ډاټا په مستقیم ډول له R څخه PowerShell ته د متغیرونو په بڼه وګرځوئ، مګر دا ستونزمن کار دی، او د منځمهاله csvs درلودل د یو چا سره د منځمهاله پایلو ډیبګ او شریکول اسانه کوي).
  • د R په کارولو سره، موږ د هغو ساحو لپاره معتبر پیرامیټونه جوړوو چې ارزښتونه یې موږ چک کوو. - موږ د کلمې سند رامینځته کوو چې د معلوماتو لیک کې د ننوتلو لپاره به د دې ساحو ارزښتونه ولري ، کوم چې به د همکارانو پوښتنو ته ځواب وي "نه ، مګر زه باید دا څنګه ډک کړم؟"
  • موږ د R په کارولو سره د csv څخه د ټولو VMs لپاره ډیټا پورته کوو ، ډیټا فریم رامینځته کوو ، غیر ضروري ساحې لرې کوو او د معلوماتو xlsx سند رامینځته کوو چې د ټولو VMs لپاره لنډیز معلومات ولري ، کوم چې موږ شریکې سرچینې ته اپلوډ کوو.
  • موږ د ټولو VMs لپاره ډیټا فریم کې د ساحو د ډکولو سموالي لپاره ټول چکونه پلي کوو او یو جدول رامینځته کوو چې په غلط ډول ډک شوي ساحو سره یوازې VMs لري (او یوازې دا ساحې).
  • موږ د VMs پایلې لیست بل PowerShell سکریپټ ته لیږو، کوم چې به د VM رامینځته کولو پیښو لپاره د vCenter لاګونه وګوري، کوم چې موږ ته اجازه راکوي د VM رامینځته کولو اټکل شوي وخت او ټاکل شوي جوړونکي په ګوته کړو. دا د قضیې لپاره دی کله چې هیڅوک نه مني چې دا د چا موټر دی. دا سکریپټ ګړندي کار نه کوي ، په ځانګړي توګه که چیرې ډیری لاګونه شتون ولري ، نو موږ یوازې په تیرو 2 اونیو کې ګورو ، او د کاري فلو څخه هم کار اخلو چې تاسو ته اجازه درکوي په ورته وخت کې په څو VMs کې د معلوماتو لټون وکړئ. د مثال سکریپټ د دې میکانیزم په اړه مفصلې تبصرې لري. موږ پایله په csv کې اضافه کوو ، کوم چې موږ بیا په R کې بار کوو.
  • موږ په ښکلي ډول فارمیټ شوي xlsx سند تولید کوو په کوم کې چې په غلط ډول ډک شوي ساحې به په سور کې روښانه شي ، فلټرونه به په ځینو کالمونو کې پلي شي ، او اضافي کالمونه چې مطلوب جوړونکي لري او د VM رامینځته کولو وخت به په ګوته شي.
  • موږ یو بریښنالیک رامینځته کوو ، چیرې چې موږ یو سند ضمیمه کوو چې د اعتبار وړ ساحې ارزښتونه تشریح کوي ، په بیله بیا یو میز چې په غلط ډول ډک شوي ساحو سره. په متن کې موږ په غلط ډول رامینځته شوي VMs ټولټال شمیره په ګوته کوو ، د یوې شریکې سرچینې لینک او یو هڅونکي عکس. که چیرې په غلط ډول ډک شوي VMs شتون ونلري، موږ یو بل لیک د خوشحاله هڅونکي انځور سره لیږو.
  • موږ د SQL سرور ډیټابیس کې د ټولو VMs لپاره ډیټا ثبت کوو ، د تاریخي جدولونو پلي شوي میکانیزم په پام کې نیولو سره (یو خورا په زړه پوري میکانیزم - په اړه یې نور وروسته)

په حقیقت کې سکریپټونه

د اصلي 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
}

د پاور شیل سکریپټ چې له لاګونو څخه د مجازی ماشینونو جوړونکي او د دوی د رامینځته کیدو نیټه استخراج کوي

# Путь к файлу, из которого будем доставать список 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 په کارولو سره د مجازی ماشینونو روغتیا په اړه ورځني راپورونه

د وینډوز مهالویش تنظیم کولو په اړه یو په زړه پوری نزاکت هم شتون درلود. دا ناشونې وه چې سم حقونه او ترتیبات ومومئ نو هرڅه به لکه څنګه چې باید پیل شي. د پایلې په توګه، د R کتابتون وموندل شو، کوم چې پخپله د R سکریپټ پیل کولو لپاره دنده رامینځته کوي او حتی د لاګ فایل په اړه هم نه هیروي. بیا تاسو کولی شئ دنده په لاسي ډول سم کړئ.

د دوه مثالونو سره د 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 فعالیت - د سیسټم نسخه لنډمهاله میز - ژغورنې ته راغلی. دا معمولا د لنډمهاله (نه موقتي) میزونو په توګه ژباړل کیږي.

تاسو کولی شئ په تفصیل سره ولولئ د مایکروسافټ رسمي اسناد.

په لنډه توګه، موږ یو جدول جوړوو، ووایو چې موږ به دا د نسخې سره ولرو، او SQL سرور په دې جدول کې د نیټې وخت 2 اضافي کالمونه رامینځته کوي (د ریکارډ جوړیدو نیټه او د ریکارډ د ختمیدو نیټه) او یو اضافي جدول چې په کې بدلون راځي. لیکل کیږي. د پایلې په توګه، موږ تازه معلومات ترلاسه کوو او د ساده پوښتنو له لارې، چې مثالونه یې په اسنادو کې ورکړل شوي، موږ کولی شو د یو ځانګړي مجازی ماشین د ژوند دورې، یا په یو ټاکلي وخت کې د ټولو VMs حالت وګورو. پر وخت.

د فعالیت له نظره، اصلي میز ته د لیکلو لیږد به تر هغه وخته بشپړ نشي چې لنډمهاله میز ته د لیکلو لیږد بشپړ شي. هغوی. په میزونو کې د ډیری لیکلو عملیاتو سره ، دا فعالیت باید په احتیاط سره پلي شي ، مګر زموږ په قضیه کې دا واقعیا ښه شی دی.

د دې لپاره چې میکانیزم په سمه توګه کار وکړي، زه باید په R کې د کوډ یوه کوچنۍ ټوټه اضافه کړم چې د ټولو VMs ډیټا سره به نوی جدول په ډیټابیس کې زیرمه شوي سره پرتله کړي او یوازې بدل شوي قطارونه یې ولیکي. کوډ په ځانګړي ډول هوښیار ندی؛ دا د پرتله کولوDF کتابتون کاروي ، مګر زه به یې لاندې هم وړاندې کړم.

ډیټابیس ته د معلوماتو لیکلو لپاره 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)

ټول

د سکریپټ پلي کولو په پایله کې، نظم د څو میاشتو په اوږدو کې بحال او ساتل شوی و. ځینې ​​​​وختونه په غلط ډول ډک شوي VMs څرګندیږي ، مګر سکریپټ د ښه یادونې په توګه کار کوي او یو نادر VM په پرله پسې 2 ورځو لیست کې راځي.

د تاریخي معلوماتو د تحلیل لپاره هم زمینه برابره شوه.

دا روښانه ده چې د دې ډیری برخه په زنګون کې نه پلي کیدی شي ، مګر د ځانګړي سافټویر سره ، مګر دا دنده په زړه پوري وه او یو څوک شاید ووایی ، اختیاري.

R یو ځل بیا ځان د یوې غوره نړیوالې ژبې په توګه ښودلی، کوم چې نه یوازې د احصایوي ستونزو د حل لپاره مناسب دی، بلکې د نورو معلوماتو سرچینو ترمنځ د غوره "پرت" په توګه هم کار کوي.

د R او PowerShell په کارولو سره د مجازی ماشینونو روغتیا په اړه ورځني راپورونه

سرچینه: www.habr.com

Add a comment