Relatórios diários do status da máquina virtual com R e PowerShell


Entrada


Bom dia Há meio ano, estamos executando um script (mais precisamente, um conjunto de scripts) que gera relatórios sobre o estado das máquinas virtuais (e não apenas). Decidi compartilhar a experiência de criação e o próprio código. Conto com críticas e com o fato de que esse material pode ser útil para alguém.


Necessita de formação


Temos muitas máquinas virtuais (cerca de 1500 VMs distribuídas no terceiro vCenter). Novos são criados e antigos são excluídos com bastante frequência. Para preservar a ordem, vários campos personalizados foram adicionados ao vCenter para dividir as VMs em subsistemas, indicar se elas são de teste, assim como por quem e quando. O fator humano levou ao fato de que mais da metade dos carros ficou com campos vazios, o que complicou o trabalho. A cada seis meses, alguém surtava, começava a trabalhar na atualização desses dados, mas o resultado deixou de ser relevante por uma semana e meia.
Esclarecerei imediatamente que todo mundo entende que deve haver aplicativos para criar máquinas, um processo para criá-las etc. etc. E enquanto todo esse processo é seguido rigorosamente e em ordem. Infelizmente, este não é o nosso caso, mas este não é o assunto do artigo :)


Em geral, foi decidido automatizar a verificação da correção do preenchimento dos campos.
Decidimos que uma carta diária com uma lista de máquinas preenchidas incorretamente para todos os engenheiros responsáveis ​​e seus superiores seria um bom começo.


Nesse ponto, um dos colegas já havia implementado um script do PowerShell, que todos os dias, em uma programação, coletava informações em todas as máquinas de todos os vCenter-s e formava 3 documentos csv (cada um em seu próprio vCenter), dispostos em um disco compartilhado. Decidiu-se tomar esse script como base e complementá-lo com verificações usando a linguagem R, com a qual eu tinha alguma experiência.


No processo de finalização, a solução ficou coberta de informações por correio, um banco de dados com as tabelas principais e históricas (mais sobre isso mais adiante), além de analisar os logs do vSphere para encontrar os criadores reais da vm e a hora em que foram criados.


Para o desenvolvimento, foram utilizados o IDE RStudio Desktop e o PowerShell ISE.


O script é iniciado a partir de uma máquina virtual Windows regular.


Descrição da lógica geral.


A lógica geral dos scripts é a seguinte.


  • Coletamos dados em máquinas virtuais usando o script do PowerShell, chamado via R, o resultado é combinado em um csv. A interação inversa entre idiomas é feita da mesma forma. (era possível direcionar dados diretamente do R para o PowerShell na forma de variáveis, mas é difícil e, mesmo com o CSV intermediário, é mais fácil depurar e compartilhar resultados intermediários com alguém).
  • Usando R, formamos parâmetros válidos para os campos cujos valores estamos verificando. - Formamos um documento do Word que conterá os valores desses campos para inserção em uma carta informativa que será uma resposta às perguntas dos colegas "Não está bem, mas como devo preencher isso?"
  • Carregamos dados em todas as VMs do csv usando R, formamos um quadro de dados, removemos campos desnecessários e formamos um documento xlsx de informações que conterá informações resumidas em todas as VMs que carregamos em um recurso compartilhado.
  • Para o quadro de dados de todas as VMs, aplicamos todas as verificações para corrigir o preenchimento dos campos e formamos uma tabela contendo apenas VMs com campos preenchidos incorretamente (e somente esses campos).
  • A lista resultante de VMs é enviada para outro script do PowerShell que examinará os logs do vCenter para eventos de criação de VMs, o que permitirá especificar o tempo estimado de criação da VM e o criador pretendido. É o caso quando ninguém confessa de quem é o carro. Esse script não funciona rápido, especialmente se houver muitos logs, portanto, analisamos apenas nas últimas 2 semanas e também usamos o fluxo de trabalho, que permite pesquisar informações sobre várias VMs ao mesmo tempo. No script de exemplo, há comentários detalhados sobre esse mecanismo. O resultado é adicionado ao csv, que é novamente carregado em R.
  • Formamos um documento xlsx lindamente formatado no qual os campos preenchidos incorretamente serão destacados em vermelho, os filtros serão aplicados a algumas colunas e serão indicadas colunas adicionais contendo os supostos criadores e a hora da criação da VM.
  • Formamos um email, onde colocamos um documento descrevendo os valores de campo válidos, bem como uma tabela com preenchimento incorreto. No texto, indicamos o número total de VMs criadas incorretamente, um link para um recurso compartilhado e uma imagem motivacional. Se não houver VMs preenchidas incorretamente, enviaremos outra carta com uma imagem motivacional mais alegre.
  • Registramos dados em todas as VMs no banco de dados do SQL Server, levando em consideração o mecanismo implementado das tabelas históricas (um mecanismo muito interessante - sobre o qual mais detalhadamente)

Scripts


O arquivo principal com o código para R
#     (       ) setwd("C:\\Scripts\\getVm") ####    #### 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.ru\\VM\\', 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.ru\\VM\\', 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 para obter a lista vm no PowerShell
 #       $vCenterNames = @( "vcenter01", "vcenter02", "vcenter03" ) $vCenterUsername = "myusername" $vCenterPassword = "mypassword" $filename = "C:\Scripts\getVm\data\allvm\all-vm-$(get-date -f yyyy-MM-dd).csv" $destinationSMB = "\\server.ru\myfolder$\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 do PowerShell que extrai os logs dos criadores de máquinas virtuais e suas datas de criação
 #   ,      VM $VMfilePath = "C:\Scripts\getVm\creators_VM\creators_VM_$(get-date -f yyyy-MM-dd).csv" #   ,      $filePath = "C:\Scripts\getVm\data\creators\creators-$(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" 

A biblioteca xlsx merece atenção especial, o que possibilitou tornar o anexo à carta claramente formatado (como o manual gosta), e não apenas uma tabela csv.


Criando um lindo documento xlsx com uma lista de máquinas preenchidas incorretamente
 #    #   : "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) 

A saída é algo como isto:




Havia também uma nuance interessante na configuração do agendador do Windows. Não deu certo para escolher os parâmetros corretos de direitos e configurações para que tudo começasse como deveria. Como resultado, foi encontrada a biblioteca R, que cria uma tarefa para executar o script R e nem esquece o arquivo de log. Então você pode corrigir a tarefa com canetas.


Um pedaço de código R com dois exemplos que cria uma tarefa no Agendador do 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) 

Separadamente, sobre o banco de dados


Depois de configurar o script, outras perguntas começaram a aparecer. Por exemplo, eu queria encontrar a data em que a VM foi excluída e os logs no vCenter já estavam gastos. Como o script coloca os arquivos na pasta todos os dias e não a limpa (nós as limpamos com as mãos quando lembramos), você pode examinar os arquivos antigos e encontrar o primeiro arquivo no qual esta VM não está. Mas isso não é legal.


Eu queria criar um banco de dados histórico.


A funcionalidade MS SQL SERVER foi útil - uma tabela temporal com versão do sistema. Geralmente é traduzido como tabelas temporárias (não temporárias).


Você pode ler em detalhes a documentação oficial da Microsoft .


Em resumo, criamos uma tabela, dizemos que a teremos com versão e o SQL Server cria 2 colunas de data e hora adicionais nessa tabela (a data em que o registro foi criado e a data em que o registro expirou) e uma tabela adicional na qual as alterações serão gravadas. Como resultado, obtemos informações relevantes e, por meio de consultas simples, exemplos dos quais são fornecidos na documentação, podemos ver o ciclo de vida de uma máquina virtual específica ou o estado de todas as VMs em um determinado momento.


Em termos de desempenho, a transação de gravação na tabela principal não será concluída até que a transação de gravação na tabela temporária seja concluída. I.e. em tabelas com um grande número de operações de gravação, essa funcionalidade deve ser implementada com cautela, mas, no nosso caso, é uma coisa muito legal.


Para que o mecanismo funcione corretamente, foi necessário adicionar um pequeno pedaço de código no R que comparasse a nova tabela com os dados de todas as VMs à armazenada no banco de dados e gravasse apenas linhas alteradas. O código não é muito complicado, ele usa a biblioteca compareDF, mas também darei a seguir.


Código R para gravar dados no banco de dados
 #   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) 

Total


Como resultado da introdução do script, a ordem foi mantida e mantida por vários meses. Às vezes, VMs preenchidas incorretamente aparecem, mas o script serve como um bom lembrete e uma VM rara entra na lista por 2 dias seguidos.


Também foi feita uma reserva para a análise de dados históricos.


É claro que muito disso pode ser realizado não "de joelhos", mas com software especializado, mas a tarefa foi interessante e, pode-se dizer, opcional.


R mais uma vez provou ser uma linguagem universal maravilhosa, perfeita não apenas para resolver problemas estatísticos, mas também atua como uma excelente "disposição" entre outras fontes de dados.


Source: https://habr.com/ru/post/pt454400/


All Articles