R ۽ PowerShell استعمال ڪندي ورچوئل مشينن جي صحت تي روزاني رپورٽون

R ۽ PowerShell استعمال ڪندي ورچوئل مشينن جي صحت تي روزاني رپورٽون

جائز آهي

منجهند جو سلام. اڌ سال لاءِ ھاڻي اسان ھڪ اسڪرپٽ ھلائي رھيا آھيون (يا بلڪه اسڪرپٽ جو ھڪڙو سيٽ) جيڪو ورچوئل مشينن جي حالت تي رپورٽون ٺاھي ٿو (۽ نه رڳو). مون پنهنجي تخليق جو تجربو ۽ ڪوڊ پاڻ کي شيئر ڪرڻ جو فيصلو ڪيو. مون کي تنقيد جي اميد آهي ۽ اهو مواد ڪنهن لاء مفيد ٿي سگهي ٿو.

ضرورت جي ٺهڻ

اسان وٽ ڪيتريون ئي ورچوئل مشينون آهن (اٽڪل 1500 VMs ورهايل 3 vCenters ۾). نوان ٺاهيا ويندا آهن ۽ پراڻا اڪثر ڊهي ويندا آهن. آرڊر برقرار رکڻ لاءِ، VMs کي سب سسٽم ۾ ورهائڻ لاءِ vCenter ۾ ڪيترائي ڪسٽم فيلڊ شامل ڪيا ويا، ظاهر ڪيو ته ڇا اھي ٽيسٽ آھن، ۽ ڪنھن جي طرفان ۽ جڏھن اھي ٺاھيون ويون آھن. انساني عنصر ان حقيقت جو سبب بڻيو ته اڌ کان وڌيڪ مشينون خالي ميدانن سان رهجي ويون، جنهن ڪم کي پيچيده ڪري ڇڏيو. هر ڇهن مهينن ۾ هڪ ڀيرو، ڪو ماڻهو پريشان ٿي ويو ۽ هن ڊيٽا کي اپڊيٽ ڪرڻ تي ڪم ڪرڻ شروع ڪيو، پر نتيجو هڪ اڌ هفتي کان پوء لاڳاپيل ٿيڻ بند ٿي ويو.
مون کي فوري طور تي واضح ڪرڻ ڏيو ته هرڪو اهو سمجهي ٿو ته مشينن جي تخليق لاءِ ايپليڪيشنون هجڻ گهرجن، انهن جي تخليق لاءِ هڪ عمل وغيره. ۽ ايئن. ۽ ساڳئي وقت، هرڪو سختي سان هن عمل جي پيروي ڪري ٿو ۽ هر شيء ترتيب ۾ آهي. بدقسمتي سان، هتي اهو معاملو ناهي، پر اهو مضمون جو موضوع ناهي :)

عام طور تي، فيصلو ڪيو ويو ته خودڪار ڪرڻ جي چڪاس ڪرڻ جي درستي کي فيلڊ ۾ ڀرڻ جي.
اسان فيصلو ڪيو ته روزانو هڪ خط غلط طور تي ڀريل مشينن جي فهرست سان سڀني ذميوار انجنيئرن ۽ انهن جي مالڪن کي ڏيڻ هڪ سٺي شروعات هوندي.

ان موقعي تي، منهنجي هڪ ساٿي اڳ ۾ ئي 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 ۾، جنهن کي اسين ٻيهر آر ۾ لوڊ ڪريون ٿا.
  • اسان هڪ خوبصورت فارميٽ ٿيل xlsx دستاويز ٺاهيندا آهيون جنهن ۾ غلط ڀريل فيلڊ ڳاڙهي رنگ ۾ نمايان ڪيا ويندا، فلٽر ڪجهه ڪالمن تي لاڳو ڪيا ويندا، ۽ اضافي ڪالمن ۾ شامل ڪيا ويندا جن ۾ گهربل تخليق ڪندڙ ۽ VM جي تخليق جو وقت اشارو ڪيو ويندو.
  • اسان هڪ اي ميل ٺاهيندا آهيون، جتي اسان هڪ دستاويز ڳنڍيندا آهيون جنهن ۾ صحيح فيلڊ جي قيمتن کي بيان ڪيو ويندو آهي، انهي سان گڏ هڪ ٽيبل سان گڏ غلط طور تي ڀريل فيلڊ سان. متن ۾ اسان غلط طور تي ٺاهيل VMs جو ڪل تعداد، ھڪڙي حصيداري وسيلن جي ھڪڙي لنڪ ۽ ھڪڙي متحرڪ تصوير ڏيکاري ٿو. جيڪڏهن ڪو به غلط طور تي ڀريل VMs نه آهن، اسان هڪ ٻيو خط موڪليندا آهيون هڪ خوش حوصلي واري تصوير سان.
  • اسان SQL سرور ڊيٽابيس ۾ سڀني VMs لاءِ ڊيٽا رڪارڊ ڪريون ٿا، تاريخي جدولن جي لاڳو ڪيل ميکانيزم کي مدنظر رکندي (هڪ تمام دلچسپ ميکانيزم - جنهن بابت وڌيڪ بعد ۾)

اصل ۾ اسڪرپٽ

مکيه آر ڪوڊ فائل

# Путь к рабочей директории (нужно для корректной работы через виндовый планировщик заданий)
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 استعمال ڪندي ورچوئل مشينن جي صحت تي روزاني رپورٽون

ونڊوز شيڊولر کي ترتيب ڏيڻ بابت پڻ هڪ دلچسپ nuance هو. اهو ناممڪن هو ته صحيح حق ۽ سيٽنگون ڳولڻ لاء ته جيئن هر شيء شروع ٿئي ها. نتيجي طور، آر لائبريري ملي وئي، جيڪا پاڻ هڪ آر اسڪرپٽ کي هلائڻ لاء ڪم ٺاهي ٿي ۽ لاگ فائل جي باري ۾ به نه وساريو. پوء توھان ڪم کي دستي طور تي درست ڪري سگھو ٿا.

آر ڪوڊ جو هڪ ٽڪرو ٻن مثالن سان جيڪو ونڊوز شيڊيولر ۾ ڪم ٺاهي ٿو

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 اضافي ڊيٽ ٽائيم ڪالم ٺاهي ٿو (تاريخ رڪارڊ ٺاهيو ويو ۽ رڪارڊ جي ختم ٿيڻ جي تاريخ) ۽ هڪ اضافي ٽيبل جنهن ۾ تبديليون. لکيو ويندو. نتيجي طور، اسان کي تازه ترين معلومات ملي ٿي ۽، سادي سوالن جي ذريعي، جن جا مثال دستاويز ۾ ڏنل آهن، اسان يا ته هڪ مخصوص ورچوئل مشين جي زندگيءَ جي چڪر، يا ڪنهن خاص نقطي تي سڀني VMs جي حالت ڏسي سگهون ٿا. وقت سر.

ڪارڪردگي جي نقطه نظر کان، مکيه ٽيبل تي لکڻ جي ٽرانزيڪشن مڪمل نه ٿيندي جيستائين عارضي ٽيبل تي لکڻ جي ٽرانزيڪشن مڪمل نه ٿيندي. اهي. ٽيبل تي وڏي تعداد ۾ لکڻ جي عملن سان، هن ڪارڪردگي کي احتياط سان لاڳو ڪيو وڃي، پر اسان جي صورت ۾ اهو هڪ تمام سٺو شيء آهي.

ميڪانيزم کي صحيح ڪم ڪرڻ لاءِ، مون کي R ۾ ڪوڊ جو هڪ ننڍڙو ٽڪرو شامل ڪرڻو هو جيڪو سڀني VMs جي ڊيٽا سان گڏ ڊيٽابيس ۾ ذخيرو ٿيل هڪ سان نئين ٽيبل جو مقابلو ڪندو ۽ ان ۾ صرف تبديل ٿيل قطارون لکندو. ڪوڊ خاص طور تي هوشيار نه آهي؛ اهو استعمال ڪري ٿو compareDF لائبريري، پر مان پڻ ان کي هيٺ پيش ڪندس.

ڊيٽابيس ۾ ڊيٽا لکڻ لاءِ آر ڪوڊ

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

تبصرو شامل ڪريو