Quantcast
Channel: My Cloud-(R)Evolution
Viewing all 153 articles
Browse latest View live

Hello Veeam Availability Console 2.0

$
0
0

Heute konnte ich mir dank des Veeam Vanguard Programms eine sehr gute Session von Clint Wyckoff zum Thema Veeam Availability Console 2.0 auf der VeeamOn 2017 ansehen. Es steht für mich außer Frage, dass Veeam sehr viel Liebe in dieses Thema gesteckt hat und auch bereits ein Tolles Produkt geliefert hat (noch RC Status), welches den Veeam Service Providern und Veeam Enterprise Kunden vieles Ihrer Arbeit erleichtern wird und sogar neue Möglichkeiten an Services schaffen wird. Die Frage die sich mir jedoch sofort aufgedrängt hat ist, bedeutet Hello Veeam Availability Console 2.0 auch Bye Veeam Enterprise Manager?
Clint Wyckoff und Rick Vanover konnten jedoch versichern, dass die beiden Produkte parallel gepflegt werden und jedes für sich seine Daseinsberechtigung hat. Veeam Enterprise Manager wird zukünftig das zuhause der Self-Service Funktionalitäten sein und Veeam Availability Console (ehemals Managed Backup Portal) ehr das Zentrale Management der Agents, Backup Server, Tenants, Policys, etc. sein.

Meine Sorgen um das ersetzen des Veeam Enterprise Manager durch Veeam Availability Console 2.0 kommen daher, dass ich aus eigener Erfahrung weiß wie viel Aufwand die Veeam Service Provider in die Nutzung der Restful  API des Enterprise Managers zur Provisionierung und Überwachung Ihrer Veeam Cloud Connect Umgebungen gesteckt haben (Hier ein eigenes kleines Beispiel).

Hello Veeam Availability Console 2.0

Quelle: Evaluator’s Guide for Service Providers

Nichts desto trotz hat auch bereits der erste, kurze Blick auf die Restful API der Veeam Availability Console 2.0 gezeigt, dass hier sehr viele parallelen vorhanden sind. Ich hoffe es folgt hierzu bald ein etwas ausführlicherer Beitrag…

Hello Veeam Availability Console 2.0 – Links

RC Download – Veeam Forum

Step by Step Guide Veeam Availability Console Install – Blog Beitrag von Christopher Glémot

Good summary of some of the key announcements from this morning keynote sessions – Veeam News

 

The post Hello Veeam Availability Console 2.0 appeared first on my cloud-(r)evolution.

Flattr this!


Veeam VeeamON 2017

$
0
0

Ich hatte letzte Woche das große Vergnügen an der Veeam VeeamON 2017 in New Orleans im Zuge des Veeam Vanguard Programms teilzunehmen. Daher muss ich an dieser Stelle auch noch einmal herausstellen, was das Wichtigste war, dass ich letzte Woche mitgenommen habe – Das Veeam Vanguard Programm ist absolut großartig!

Vielen Dank an Veeam, alle Veeam Mitarbeiter und die anderen Vanguard `s die mich sehr familiär in New Orleans empfangen haben. Den Veeam Kollegen auch noch mal ein großer Dank, dass Sie Ihre knappe Zeit geopfert haben und uns einen tiefen Einblick in die Produkte sowie die Strategie von Veeam gewährt haben. Besonderer Dank gilt: Rick VanoverAnthony SpiteriClint WyckoffMichael CadeMichael White und Anton Gostev.

Zusammenfassung Veeam VeeamON 2017

Allgemein

Grundlegend muss ich sagen, dass ich die Veeam VeeamON 2017 im Gegensatz zur VMworld (Europe) als angenehmer empfand, vermutlich wegen der geringeren Größe. Mit ca. 3000 Besuchern war es wesentlich überschaubarer. Man kommt in alle Vorträge (bei VMware tlw. lange vorher ausgebucht) und es ist mehr Zeit zum Netzwerken und Austauschen mit Veeam Mitarbeitern sowie Besuchern vorhanden. Der einzige Wermutstropfen ist, dass die Qualität der Vorträge im Durchschnitt nicht ganz an die auf der VMworld heranreicht. Nur damit das nicht falsch verstanden wird, es gab auch wirklich viele herausragende Sessions!

Wie auf solchen Veranstaltungen üblich, wurden auch auf der Veeam VeeamON 2017 die Tage mit einer General Sessions gestartet, welche von Partnern wie VMware, Microsoft, HPE und Cisco unterstützt wurden.

Veeam VeeamOn 2017 - General Session Microsoft

Veeam VeeamOn 2017 - General Session HPE

Ausrichtung von Veeam

Auch in den offiziellen Folien von Veeam ist ganz klar, dass die Strategie eindeutig in Richtung Enterprise Markt geht. Das wird unter anderem durch kommende Applikations-Unterstützung von Oracle RMAN, SAP HANA und der geplanten Unterstützung von NetApp NDP untermauert.
Es wird auch das Kern-Produkt nun immer weiter von einem Backup Produkt zur umfassenden Availability Suite umgebaut. Produkte und Features wie CDP (Continous Data Protection) für VMware, Veeam PN (PowerNetwork) und der Availability Orchestrator runden das Portfolio hierfür stimmig ab.

Sehr positiv finde ich auch, dass die „must have“ Cloud Ausrichtung nicht nur Richtung Azure geht, sondern auch die Partner im Bereich Veeam Cloud Connect und Veeam Backup für Office 365 mit neuen Features nicht vergessen werden.

Ankündigungen auf der Veeam VeeamON 2017

Veeam Availabilty Suite v10

  • Veeam CDP (Continous Data Protection)

Hierbei handelt es sich um eine Erweiterung der bereits bekannten Replikation von Veeam. Das Feature funktioniert nur mit VMware, da die vSphere APIs for IO Filtering genutzt wird, um alle IOs einer VM auf eine Sekundäre zu spiegeln. Es kann damit nahezu ein synchroner Spiegel mit einem RPO von 2-3 Sekunden erreicht werden. Es können zusätzlich zu dem letzten bekannten Stand auch noch weitere Konsistenzpunkte hergestellt werden. Ein Konsistenzpunkt kann sogar auf Wunsch mit Applikationskonsitenz erstellt werden. Die Daten werden im Ziel Datastore als Delta Disks gespeichert (keine Snapshots).

Veeam VeeamOn 2017 - CDP 1 Veeam VeeamOn 2017 - NAS Backup 3
  • NAS Backup

Über einen in v10 neu eingeführten Proxy Typ hat man nun die Möglichkeit mit Veeam auch NFS und SMB Shares zu sichern. Dieses Feature hört sich erst mal ziemlich trivial an, wurde aber sehr aufwendig implementiert, um eine effiziente Ablage (Sortierung nach Blockgröße) und vernünftige Skalierung (mit mehreren Proxys) zu ermöglichen.

Veeam VeeamOn 2017 - NAS Backup 1 Veeam VeeamOn 2017 - NAS Backup 2 Veeam VeeamOn 2017 - NAS Backup 3
  • Archive Repositority

Für mich persönlich ein richtig geniales Feature! Archiv Repositories können einem Scale-Out-Repository zur Auslagerung hinzugefügt werden. Anhand von einer zugewiesenen Policy werden dann entweder alte oder alle Backups dorthin verschoben oder kopiert. Die Archiv Repositories können sogar nicht nur wie hauptsächlich angepriesen ein Object Storage wie Amazon S3 sein, sondern auch jedes andere eingebundene Veeam Repository oder ein Tape sein.

Veeam VeeamOn 2017 - Archive Repositority 2 Veeam VeeamOn 2017 - Archive Repositority 3
  • Veeam Agents integration

Bisher waren physikalische Server leider immer ein Problem mit Veeam. Das wird sich nun mit der v10 endgültig ändern, denn die bereits bekannten Windows Agents lassen sich nun auch in der Management Konsole zentral verwalten und wenn gewünscht automatisch mit Backup Jobs versehen.
Mit der Agent Unterstützung kommt für mich persönlich auch die Unterstützung von virtuellen Microsoft Failover Clustern hinzu. Diese können unter VMware nicht über Snapshot gesichert werden und sind daher bisher problematisch gewesen.

Verteilung der Agenten wird optional sogar per AD-Sync funktionieren.  Auch die Backup Job Zuordnung kann pro Gruppe automatisch passieren (mit und ohne AD-Sync).

 

Veeam VeeamOn 2017 - Agent Integration 1 Veeam VeeamOn 2017 - Agent Integration 2 Veeam VeeamOn 2017 - Agent Integration 3
  • Oracle RMAN Backup

Viel zu sehen war zu dem Thema leider noch nicht. Wichtig ist aber, dass der Veeam Explorer for Oracle auch per RMAN wie gewohnt funktioniert.

 

  • Universal Storage API

Hierbei handelt es sich nicht um ein Feature im klassischen Sinne, sondern um ein Framework, welches den Storage Herstellern ermöglichen soll die Unterstützung für ihr Array schneller in das Produkt zu integrieren. Die Erweiterung wird durch den Storage Hersteller selbst entwickelt aber dann von Veeam zertifiziert und supportet.

 

  • DRaaS Erweiterung

Bei dieser Ergänzung handelt es sich um eine zusätzliche Schnittstelle von Veeam Cloud Connect Replication, welche es den Service Providern ermöglichen wird die Kunden-Replikation im VMware vCloud Director zu integrieren. Ohne dieses Feature musste der Kunden den Service Provider kontaktieren um z.B. eine VM zu resetten.
Durch die Kopplung werden dem Service Provider ganz neue Möglichkeiten eines runden Produktes eröffnet. Der Kunde kann zum Beispiel seine Replikate zusammen mit bereits laufenden VMs im VMware vCloud Director Portal verwalten und die passenden Netze konfigurieren. Die Schnittstelle wird wohl auch beinhalten, dass zur Abrechnung das vCD Modell verwendet werden kann und nicht nur der Veeam eigene Billing-Plan.

 

  • Veeam Content Pack für vRealize Log Insight

Bei einem Content Pack für VMware vRealize Log Insight handelt es sich um ein “Plugin” in das Syslog Produkt von VMware. Mit einem Content Pack kommen vom Hersteller vorgefertigte Darstellungen, Auswertungen und Alarme rund um die Logs oder Events des jeweiligen Produkts. Für mich ebenfalls ein großer Schritt in Richtung des Enterprise Markts!

Zu dem Thema gab es auch schon ein eigenes kleines Projekt von mir: vRealize Log Insight Content Pack für Veeam
Im Gegensatz zu meinem Ansatz greift jedoch das offizielle Content Pack anscheinend nur auf die Eventlogs zu.

Auf der Veeam Seite ist auch bereits der Download zu finden: Veeam Backup & Replication Content Pack für vRealize Log Insight

In der Version 1.0 fehlen aber mindestens noch die Agent Gruppen. Daher wird wohl noch eine neuere Version kommen vor dem Offiziellen Release.

\\One4all.lan\one4all$\Home\MKUS\Desktop\Veeam VeeamOn 2017 - vRealize Log Insight CP

  • Veeam Enterprise Manager Self Service

Analog zu der VMware vCloud Director Self Service Integration wird der neue Enterprise Manager nun auch VMware vSphere Nutzern ermöglichen, Backup Jobs ihrer eigenen VMs anzulegen. Rechte werden aus dem VMware vCenter gezogen.

Veeam Availablity for AWS

Zu diesem Produkt kann ich leider nur die Folie wiedergeben, da ich weder in AWS EC2 einen tieferen Einblick habe noch eine weitere Session dazu besuchen konnte.

Die Folie hat gesagt, dass das Produkt eine Agentenlose Sicherung von Amazon AWS Applikationen und Daten ermöglichen wird. Umgesetzt wird das wohl über den Cloud Protection Manager von N2W Software: http://www.n2ws.com/products-services/cloud-protection-manager.html

Veeam Availability Console 2.0

Dieses Produkt wird den Veeam Service Providern und größeren Enterprise Kunden nach der Veröffentlichung sehr viel Arbeit bei der Verwaltung ihrer Veeam Umgebung erleichtern. Entstanden ist die Version 2.0 aus dem Veeam Managed Backup Portal in AWS. Anders als in der Version 1.0 kann die Availabllity Console 2.0 nun auch lokal installiert werden und ermöglicht die Verwaltung aller Veeam Backup & Replication Jobs, Veeam Agenten und der kompletten Veeam Cloud Connect Infrastruktur bis hin zum Endkunden. Viele der Konfigurationen können per Policy abgewickelt werden.

Wichtig ist, die Veeam Availabllity Console wird den Veeam Enterprise Manager nicht ersetzen.

Aktuell befindet sich das Produkt noch im RC Status, ist aber einen Test wert: Veeam Availabllity Console 2.0 RC

Veeam Availability Orchestartor

Der Availablity Orchestrator wird als separates Produkt die integrierten Failover Szenarien von Veeam Backup & Replication enorm erweitern. Einen Schwerpunkt hat Veeam bei der Entwicklung des Produkts auf das Erstellen von Reports und automatische Dokumentationen gelegt.

Ein vergleichbares Produkt wäre der VMware Site Recovery Manager. Im Gegensatz zu dem VMware Produkt greift aber der Availablity Orchestrator auf Veeam Replikas zu. Diese werden wie gewohnt in Veeam Backup & Replication angelegt, dann aber mit dem Orchestrator weiter konfiguriert.

Mit dem Availablity Orchestrator zusammen kommt ebenfalls noch eine abgespeckte Version von Veeam ONE, diese kann und wird aber nur intern verwendet.

Veeam Disaster Recovery in Microsoft Azure

Ähnlich wie bei dem AWS Thema fehlen mir hierbei etwas die Bezüge aus der Praxis für das Produkt.
Nichts desto trotz kann ich sagen, dass das Produkt eine Kombination aus Direct Restore to Microsoft Azure und Veeam PowerNetwork (PN) ist.

Durch das Veeam Vangurad Programm konnte ich bereits einige Wochen vor der Veeam VeeamON 2017 einen Blick auf das neue Produkt Veeam PN werfen und war bei beiden Live Demos restlos begeistert. Veeam PN ist eine Art von VPN Management. Für den Setup wird entweder in Azure oder Lokal ein Veeam PN Hub installiert (Software Appliance), dann werden beliebige Standorte oder Clients angebunden. Alles sieht sehr simpel und robust aus.

In Verbindung mit Veeam Disaster Recovery in Microsoft Azure wird Veeam PN verwendet, um die wiederhergestellten Systeme mit dem ursprünglichen Netzwerk zu verbinden und per NAT darauf zuzugreifen.

Veeam VeeamOn 2017 - VeeamPN for DR to Azure

Veeam Backup for Microsoft Office 365 v1.5

Als Veeam mit der Version 1.0 mit dem Produkt kam, war meine erste Kritik, dass es so nicht für Service Provider geeignet ist. Veeam hat jetzt aber mit der Version 1.5 seine Hausaufgaben gemacht und das Produkt sehr skalierbar, mit einer REST API, einem PowerShell Modul und robuster Multi-Tenancy Fähigkeit für Service Provider neu aufgelegt.

Die Sicherung beschränkt sich weiter auf Email.

Veeam Backup for Microsoft Office 365 v2

Auch, wenn die Version 2.0 auf der Veeam VeeamON 2017 noch etwas in der Ferne laf, hat Veeam bereits jetzt angekündigt mit dem Release SharePoint Online und OneDrive in Office 365 ebenfalls sichern zu können.

Weitere Quellen zur Veeam VeeamON 2017:

The post Veeam VeeamON 2017 appeared first on my cloud-(r)evolution.

Flattr this!

My Custom Plaster Template

$
0
0

Um meine PowerShell Projekte endlich etwas zu vereinheitlichen, stand schon länger das Erstellen eines Custom Plaster Template auf meiner ToDo Liste. Das Plaster Projekt selbst kenne ich schon etwas, habe aber leider bisher nicht die Zeit gefunden mich damit genauer zu beschäftigen. Somit hatte also am Ende der Langstreckenflug nach New Orleans etwas sehr Positives… Nämlich die Einarbeitung in dieses geniale Tool.

Was ist Plaster

Die eigene Projektbeschreibung bedarf keiner weiteren Erläuterung:

Plaster is a template-based file and project generator written in PowerShell. Its purpose is to streamline the creation of PowerShell module projects, Pester tests, DSC configurations, and more. File generation is performed using crafted templates which allow the user to fill in details and choose from options to get their desired output.

Nachdem das Plaster Modul aus der PowerShell Gallery gezogen ist (ab PowerShell 5), kann man auch bereits ohne weitere Konfiguration mit dem Standard-Template sein erstes Projekt erzeugen:

Install-Module -Name Plaster

Invoke-Plaster -TemplatePath (Get-PlasterTemplate).TemplatePath -DestinationPath <String>

Ausführliche Dokumentation zu dem Plaster Cmdlet`s findet sich im GitHub Projekt.

Mit meinem Custom Plaster Template sieht der Aufruf ähnlich aus. Nur der Pfad zu dem eigenen Template muss mitgegeben werden:

Custom Plaster Template - Execution

Das Ergebnis ist dann ein Verzeichnis mit allen nötigen Unterordnern und den gewünschten Files darin, welche auch teilweise inhaltlich durch token replacement auf das neue PowerShell Modul angepasst wurden:

C:\TEMP\MYFIRSTPROJECT
│   myFirstProject.psd1
│   myFirstProject.psm1
│   README.md
│
├───.vscode
│       settings.json
│       tasks.json
│
├───docs
│   │   index.rst
│   │
│   └───features
├───helper
│       myFirstProject.Create-Docs.ps1
│       Update-ModuleManifestData.ps1
│       Update-PowerShellGallery.ps1
│
├───media
└───tests
        myFirstProject.Tests.ps1

Was soll mein Custom Plaster Template beinhalten

Da ich sehr gerne mit VSCode an meinen Skripten arbeite, sollte gleich bei der Projekterstellung eine tiefe Integration erfolgen. Dafür soll in jedem Fall die Nutzung von Pester Tests und Read the Docs Dokumentationen vereinfacht werden.

VSCode Integration

Der einfachste Weg, die Nutzung solcher Tools zu vereinfachen ist die Einbindung als Tasks in VSCode.

Meine Tasks:

  • Pester Test
  • Read The Docs Generierung
  • Module Manifest File aktualisieren
    • Patch
    • Minor
    • Major

Aber auch eine kleine Grundkonfiguration für den VSCode Workspace sollte beinhaltet sein.

VSCode Tasks

Für mein task.json habe ich mich der Vorlage aus dem Standard-Template bedient und dieses um meine zusätzlichen Tasks erweitert.

// Available variables which can be used inside of strings.
// ${workspaceRoot}: the root folder of the team
// ${file}: the current opened file
// ${relativeFile}: the current opened file relative to workspaceRoot
// ${fileBasename}: the current opened file's basename
// ${fileDirname}: the current opened file's dirname
// ${fileExtname}: the current opened file's extension
// ${cwd}: the current working directory of the spawned process
{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
	"version": "0.1.0",

	// Start PowerShell
    "windows": {
        "command": "${env.windir}\\sysnative\\windowspowershell\\v1.0\\PowerShell.exe"
    },
    "linux": {
        "command": "/usr/bin/powershell"
    },
    "osx": {
        "command": "/usr/local/bin/powershell"
    },

	// The command is a shell script
	"isShellCommand": true,

	// Show the output window always
	"showOutput": "always",

    "args": [
        "-NoProfile", "-ExecutionPolicy", "Bypass"
    ],

    // Associate with test task runner
    "tasks": [
        {
            "taskName": "CreateDocs",
            "suppressTaskName": true,
            "isTestCommand": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking CreateDocs'; ./helper/*.Create-Docs.ps1;",
                "Invoke-Command { Write-Host 'Completed CreateDocs task in task runner.' }"
            ]
        },
        {
            "taskName": "UpdateManifestData-Patch",
            "suppressTaskName": true,
            "isTestCommand": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking Patch UpdateManifestData'; Import-Module ./helper/Update-ModuleManifestData.ps1 -Force;",
                "Update-ModuleManifestData -Path ./*.psd1 -Patch;",
                "Invoke-Command { Write-Host 'Completed Patch UpdateManifestData task in task runner.' }"
            ]
        },
        {
            "taskName": "UpdateManifestData-Minor",
            "suppressTaskName": true,
            "isTestCommand": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking Minor UpdateManifestData'; Import-Module ./helper/Update-ModuleManifestData.ps1 -Force;",
                "Update-ModuleManifestData -Path ./*.psd1 -Minor;",
                "Invoke-Command { Write-Host 'Completed Minor UpdateManifestData task in task runner.' }"
            ]
        },
        {
            "taskName": "UpdateManifestData-Major",
            "suppressTaskName": true,
            "isTestCommand": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking Major UpdateManifestData'; Import-Module ./helper/Update-ModuleManifestData.ps1 -Force;",
                "Update-ModuleManifestData -Path ./*.psd1 -Major;",
                "Invoke-Command { Write-Host 'Completed Major UpdateManifestData task in task runner.' }"
            ]
        },
        {
            "taskName": "Test",
            "suppressTaskName": true,
            "isTestCommand": true,
            "showOutput": "always",
            "args": [
                "Write-Host 'Invoking Pester'; Invoke-Pester -PesterOption @{IncludeVSCodeMarker=$true};",
                "Invoke-Command { Write-Host 'Completed Test task in task runner.' }"
            ],
            "problemMatcher": [
                {
                    "owner": "powershell",
                    "fileLocation": ["absolute"],
                    "severity": "error",
                    "pattern": [
                        {
                            "regexp": "^\\s*(\\[-\\]\\s*.*?)(\\d+)ms\\s*$",
                            "message": 1
                        },
                        {
                            "regexp": "^\\s+at\\s+[^,]+,\\s*(.*?):\\s+line\\s+(\\d+)$",
                            "file": 1,
                            "line": 2
                        }
                    ]
                }
            ]
        }
	]
}

Ist das neue Projekt in VSCode geöffnet, lassen sich die Tasks über die Befehlsleiste aufrufen:

Custom Plaster Template - VSCode Tasks

Für die UpdateManifestData Tasks wird ein Skript (Update-ModuleManifestData.ps1) im Ordner helper verwendet. Dieser Ordner wird ebenfalls automatisch am Ziel erstellt.
Durch das Update-ModuleManifestData.ps1 Script wird aber nicht nur die Versionsnummer laut den Vorgaben hochgezählt, sondern auch alle Funktionen aus den psm1-Files des Projekts exportiert.

Ich verwende üblicherweise pro Funktion ein eigenes psm1 File, welches analog zur Funktion benannt ist. Darauf ist auch das Update-ModuleManifestData.ps1 Skript ausgelegt.

Die Ausgabe des Taks UpdateManifestData-Patch sieht dann mit der einen Funktion „myFirstProject“ so aus:

Custom Plaster Template - VSCode Task UpdateManifestData-Patch Output

VSCode Settings

Da es sich bei den Files in den erzeugten Projekten hauptsächlich um PowerShell Skripte handeln wird, bietet es sich an dies in den Workspace Settings als Standard festzulegen.

{
    "files.trimTrailingWhitespace": true,
    "files.defaultLanguage": "powershell"
}

Pester

Wie bereits in einem vorherigen Abschnitt ausgeführt, ist das wichtigste für mich die Integration über die VSCode Tasks. Somit kann jederzeit schnell auf die Tests zugegriffen werden.

Um das zu ermöglichen, wird in meinem Custom Plaster Template ein Basis-Test für das neue Modul erstellt.  Der Task zum Aufruf der Pester Tests ist ja bereits über das tasks.json erzeugt.

Für einen Basis-Test habe ich mich dem genialen Skript von Kevin Marquette’s blog bedient. Die spezifischen Pester Tests können dann später einfach hinzugefügt werden.

Ausgabe des Test Tasks mit Hilfe von Pester sieht dann so aus:

Custom Plaster Template - VSCode Task Test Output

Read the Docs

Auf Read the Docs bin ich ursprünglich durch den Artikel Switching to reStructuredText and ReadTheDocs for GitHub Project Documentation von Chris Wahl gekommen. Ich finde das eine tolle Möglichkeit, schnell und unkompliziert eine Basis-Doku zu erstellen und aktuell zu halten.
Zur Generierung der Files für die Dokumentation verwende ich zum einen eine etwas angewandelte Version des Skripts von Chris Wahl und zum anderen eine index.rst die als Template für ein token replacement dient.

Welcome to my <%=$PLASTER_PARAM_ModuleName%> Module
========================

This the basic documentation of the '<%=$PLASTER_PARAM_ModuleName%>' PowerShell Module.
The main documentation for the module is organized into a couple sections:

* :ref:`feature-docs`

.. _feature-docs:

.. toctree::
   :maxdepth: 2
   :glob:
   :caption: Feature Documentation

   features/*

Custom Plaster Template Manifest

Um mein Custom Plater Template zu erstellen bin ich wie folgt vorgegangen:

  • Basis-Template erzeugen

$manifestProperties = @{
    Path = $env:USERPROFILE + '\Documents\GitHub\PlasterConfig\Templates\plasterManifest.xml'
    Title = 'My Custom Plaster Template'
    TemplateName = 'MyCustomPlasterTemplate'
    TemplateVersion = '0.0.1'
    Author = 'Markus Kraus'
}

New-PlasterManifest @manifestProperties

  • Benötigte Schritte aus dem Default Template kopieren und für eigene Template adaptieren (eine weitere gute Quelle sind die zusätzlichen Beispiele im GitHub Projekt)

C:\Program Files\WindowsPowerShell\Modules\Plaster\1.0.1\Templates\NewPowerShellManifestModule\plasterManifest.xml

  • Benötigte Files in das Projekt kopieren

Es ist erforderlich, dass jedes Template in einem eigenen Order abgelegt wird.

Das fertige Schema der Projekts wird in der plasterManifest.xml festgehalten:

<?xml version="1.0" encoding="utf-8"?>
<plasterManifest
      schemaVersion="1.0" xmlns="http://www.microsoft.com/schemas/PowerShell/Plaster/v1">
      <metadata>
            <name>MyCustomPlasterTemplate</name>
            <id>8ccc688a-efd6-4729-91e7-8332291b7ad4</id>
            <version>0.0.1</version>
            <title>My Custom Plaster Template</title>
            <description></description>
            <author>Markus Kraus</author>
            <tags></tags>
      </metadata>
      <parameters>
            <parameter name='ModuleName'
                  type='text'
                  prompt='Enter the name of the module'/>

            <parameter name='Version'
                  type='text'
                  prompt='Enter the version number of the module'
                  default='0.1.0'/>

            <parameter name='AddTest'
                  type='choice'
                  prompt='Create test dir and add Pester test for module manifest validation:'
                  default='0'
                  store='text'>
                  <choice label='&amp;No'
                        help="Choose not to add Pester test support."
                        value="No"/>
                  <choice label='&amp;Yes'
                        help="Choose to add Pester test support."
                        value="Yes"/>
            </parameter>

            <parameter name='AddHelperDoc'
                  type='choice'
                  prompt='Add  helper Script and Index to create ReadTheDocs Files:'
                  default='0'
                  store='text'>
                  <choice label='&amp;No'
                        help="Choose not to add helper Files"
                        value="No"/>
                  <choice label='&amp;Yes'
                        help="Chooseot to add helper Files."
                        value="Yes"/>
            </parameter>

            <parameter name='Editor'
                  type='choice'
                  prompt='Select a editor for editor integration (or None):'
                  default='0'
                  store='text' >
                  <choice label='&amp;None'
                        help="No editor specified."
                        value="None"/>
                  <choice label='Visual Studio &amp;Code'
                        help="Your editor is Visual Studio Code."
                        value="VSCode"/>
            </parameter>
      </parameters>

      <content>
            <message>&#10;&#10;Scaffolding your PowerShell Module...&#10;&#10;&#10;</message>

            <newModuleManifest destination='${PLASTER_PARAM_ModuleName}.psd1'
                  moduleVersion='$PLASTER_PARAM_Version'
                  rootModule='${PLASTER_PARAM_ModuleName}.psm1'
                  encoding='UTF8-NoBOM'/>

            <templateFile source='MyCustomPlasterTemplate-Template.psm1'
                  destination='${PLASTER_PARAM_ModuleName}.psm1'/>

            <templateFile source='README.md'
                  destination='README.md'/>

            <file source=''
                  destination='media/'/>
            
            <file source=''
                  destination='helper/'/>

            <file source=''
                  destination='docs/'/>
            
            <file source='helper/Update-*'
                  destination='helper/'/>

            <file condition="$PLASTER_PARAM_AddHelperDoc -eq 'Yes'"
                  source=''
                  destination='docs/features'/>

            <templateFile condition="$PLASTER_PARAM_AddHelperDoc -eq 'Yes'"
                  source='helper\Create-Docs.ps1'
                  destination='helper\${PLASTER_PARAM_ModuleName}.Create-Docs.ps1'/>

            <templateFile condition="$PLASTER_PARAM_AddHelperDoc -eq 'Yes'"
                  source='docs\index.rst'
                  destination='docs\index.rst'/>                   

            <templateFile condition="$PLASTER_PARAM_AddTest -eq 'Yes'"
                  source='tests\MyCustomPlasterTemplate-BasicTest.ps1'
                  destination='tests\${PLASTER_PARAM_ModuleName}.Tests.ps1' />

            <file condition="($PLASTER_PARAM_Editor -eq 'VSCode')"
                  source='editor\VSCode\settings.json'
                  destination='.vscode\settings.json' />

            <file condition="(($PLASTER_PARAM_Editor -eq 'VSCode') -and ($PLASTER_PARAM_AddTest -eq 'Yes'))"
                  source='editor\VSCode\tasks.json'
                  destination='.vscode\tasks.json' />

            <requireModule name="Pester" condition="$PLASTER_PARAM_AddTest -eq 'Yes'" minimumVersion="3.4.0"
                  message="Without Pester, you will not be able to run the provided Pester test to validate your module manifest file.`nWithout version 3.4.0, VS Code will not display Pester warnings and errors in the Problems panel."/>

            <message>

Your new PowerShell module project '$PLASTER_PARAM_ModuleName' has been created.

            </message>

            <message condition="$PLASTER_PARAM_AddTest -eq 'Yes'">
A Pester test has been created to validate the module's manifest file.  Add additional tests to the test directory.
You can run the Pester tests in your project by executing the 'test' task.  Press Ctrl+P, then type 'task test'.

            </message>

            <message condition="$PLASTER_PARAM_AddHelperDoc -eq 'Yes'">
A Script to help you to create the Files for ReadTheDocs is added to the helper Folder.
You can run the Docs creation in your project by executing the 'CreateDocs' task.  Press Ctrl+P, then type 'task CreateDocs'.

            </message>
      </content>
</plasterManifest>

Meine Plaster  Konfiguration auf GitHub

Alle von mir verwendeten Skripte und Konfigurationen sind auch in meinem GitHub Projekt zu diesem Beitrag zu finden.

My PlasterConfig Project

 

 

Weitere Infos

The post My Custom Plaster Template appeared first on my cloud-(r)evolution.

Flattr this!

PowerCLI vCloud Director Customer Provisioning

$
0
0

Ich konnte letzte Woche endlich ein kleines Projekt fertigstellen, welches mich schon etwas länger verfolgte. Das vCloud Director Customer Provisioning mit VMware PowerCLI. Neue Kunden im VMware vCloud Director anzulegen ist wieder mal ein Paradebeispiel für eine Automation, denn es muss schnell, standardisiert und hoffentlich oft erledigt werden.

vCloud Director Customer Provisioning - PS Console

Die meisten Service Provider werden diese Aufgabe nicht unbedingt per PowerShell abbilden, sondern ehr direkt die API des VMware vCloud Director nutzen. Ich wollte jedoch mit meinem Projekt vCloud Director Customer Provisioning sehen, ob das Komplett mit VMware PowerCLI abbildbar ist. Eines schon vorweg, es ist nicht sehr komfortabel und auch nur eingeschränkt möglich.

Schritte beim vCloud Director Customer Provisioning

Die Anlage eines komplett neuen Kunden ist in mehrere Schritte gegliedert, welche teilweise in der richtigen Reihenfolge ausgeführt werden müssen.

Initial müssen allerdings erst noch die PowerShell Module geladen und der VMware vCloud Director verbunden werden:

# Import VMware PowerCLI vCD Module
Import-Module VMware.VimAutomation.Cloud

# Import My vCD Module
Import-Module .\VMware-vCD-Module\

# Connect vCD Instance
Connect-CIServer <Your vCD FQDN>

Create VMware vCloud Director Organization

Die Organisationen im VMware vCD kann man als Mandanten betrachten. Jeder Kunden hat im Normalfall seine eigene Organisation hinter der eine eigene URL und seine eigenen Benutzer sowie Ressourcen stehen.

Wie auch für die meisten weiteren Schritte gibt es in VMware PowerCLI ein natives Cmdlet für das Erstellen einer neuen Organisation: New-Org
Für meine Zwecke hat dieses Cmdlet allerdings zu wenig Möglichkeiten die Optionen der Organisation direkt beim Anlegen anzupassen.

Meine weiterführenden Optionen:

  • Catalog Publishing
  • Catalog Subscription
  • VM Quota
  • Stored VM Quota
  • VM Lease Time
  • Stored VM Lease Time
  • Password Policy Settings

Daher habe ich für das vCloud Director Customer Provisioning folgende Funktion geschrieben um alle meine Anforderungen zu erfüllen:

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function New-MyOrg {
<#
.SYNOPSIS
    Creates a new vCD Org with Default Parameters

.DESCRIPTION
    Creates a new vCD Org with Default Parameters.

    Default Parameters are:
    * Catalog Publishing
    * Catalog Subscription
    * VM Quota
    * Stored VM Quota
    * VM Lease Time
    * Stored VM Lease Time
    * Password Policy Settings

.NOTES
    File Name  : New-MyOrg.ps1
    Author     : Markus Kraus
    Version    : 1.1
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    New-MyOrg -Name "TestOrg" -FullName "Test Org" -Description "PowerCLI Test Org"

.PARAMETER Name
    Name of the New Org as String

.PARAMETER FullName
    Full Name of the New Org as String

.PARAMETER Description
    Description of the New Org as String

.PARAMETER Enabled
    Should the New Org be enabled after creation

    Default:$false

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org as string")]
        [ValidateNotNullorEmpty()]
            [String] $Name,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Name of the New Org as string")]
        [ValidateNotNullorEmpty()]
            [String] $FullName,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Description of the New Org as string")]
        [ValidateNotNullorEmpty()]
            [String] $Description,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled
    )
    Process {
        $vcloud = $DefaultCIServers[0].ExtensionData

        ## Create Objects
        $AdminOrg = New-Object VMware.VimAutomation.Cloud.Views.AdminOrg
        $orgGeneralSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgGeneralSettings
        $orgOrgLeaseSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgLeaseSettings
        $orgOrgVAppTemplateLeaseSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgVAppTemplateLeaseSettings
        $orgOrgPasswordPolicySettings = New-Object VMware.VimAutomation.Cloud.Views.OrgPasswordPolicySettings
        $orgSettings = New-Object VMware.VimAutomation.Cloud.Views.OrgSettings

        ## Admin Settings
        $adminOrg.Name = $name
        $adminOrg.FullName = $FullName
        $adminOrg.Description = $description
        $adminOrg.IsEnabled = $Enabled

        ## Org Setting
        ### General Org Settings
        $orgGeneralSettings.CanPublishCatalogs = $False
        $orgGeneralSettings.CanPublishExternally = $False
        $orgGeneralSettings.CanSubscribe = $True
        $orgGeneralSettings.DeployedVMQuota = 0
        $orgGeneralSettings.StoredVmQuota = 0
        $orgSettings.OrgGeneralSettings = $orgGeneralSettings
        ### vApp Org Setting
        $orgOrgLeaseSettings.DeleteOnStorageLeaseExpiration = $false
        $orgOrgLeaseSettings.DeploymentLeaseSeconds = 0
        $orgOrgLeaseSettings.StorageLeaseSeconds = 0
        $orgSettings.VAppLeaseSettings = $orgOrgLeaseSettings
        ### vApp Template Org Setting
        $orgOrgVAppTemplateLeaseSettings.DeleteOnStorageLeaseExpiration = $false
        $orgOrgVAppTemplateLeaseSettings.StorageLeaseSeconds = 0
        $orgSettings.VAppTemplateLeaseSettings = $orgOrgVAppTemplateLeaseSettings
        ### PasswordPolicySettings Org Setting
        $orgOrgPasswordPolicySettings.AccountLockoutEnabled = $True
        $orgOrgPasswordPolicySettings.InvalidLoginsBeforeLockout = 5
        $orgOrgPasswordPolicySettings.AccountLockoutIntervalMinutes = 30
        $orgSettings.OrgPasswordPolicySettings = $orgOrgPasswordPolicySettings

        $adminOrg.Settings = $orgSettings

        $CreateOrg = $vcloud.CreateOrg($adminOrg)

        Get-Org -Name $name | Format-Table -AutoSize
    }
}

vCloud Director Customer Provisioning - Org

Create VMware vCloud Director Organization Administrator

Um dem neuen Kunden auch Zugriff auf seine Ressourcen zu gewähren muss mindestens ein User initial angelegt werden, Im optimalen Fall ist das ein Organisations Administrator. Mit diesem User kann der Kunden dann alle weiteren User selbst anlegen und einige Einstellungen anpassen (Siehe auch: Predefined Roles and Their Rights).

Für diesen Prozess gibt es leider kein natives Cmdlet in VMware PowerCLI.

Meine Funktion zur Useranlage sieht vor, dass der User für das vCloud Director Customer Provisioning fix als Organisations Administrator angelegt wird:

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function New-MyOrgAdmin {
<#
.SYNOPSIS
    Creates a new vCD Org Admin with Default Parameters

.DESCRIPTION
    Creates a new vCD Org Admin with Default Parameters

    Default Parameters are:
    * User Role

.NOTES
    File Name  : New-MyOrgAdmin.ps1
    Author     : Markus Kraus
    Version    : 1.1
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    New-MyOrgAdmin -Name "OrgAdmin" -Pasword "Anfang!!" -FullName "Org Admin" -EmailAddress "OrgAdmin@TestOrg.local" -Org "TestOrg"

.PARAMETER Name
    Name of the New Org Admin as String

.PARAMETER FullName
    Full Name of the New Org Admin as String

.PARAMETER Password
    Password of the New Org Admin as String

.PARAMETER EmailAddress
    EmailAddress of the New Org Admin as String

.PARAMETER Enabled
    Should the New Org be enabled after creation

    Default:$false

.PARAMETER Org
    Org where the new Org Admin should be created as string

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $Name,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Password of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $Pasword,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Name of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $FullName,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="EmailAddress of the New Org Admin as String")]
        [ValidateNotNullorEmpty()]
            [String] $EmailAddress,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Org Admin should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $Org,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled
    )
    Process {

        ## Create Objects
        $OrgED = (Get-Org $Org).ExtensionData
        $orgAdminUser = New-Object VMware.VimAutomation.Cloud.Views.User

        ## Settings
        $orgAdminUser.Name = $Name
        $orgAdminUser.FullName = $FullName
        $orgAdminUser.EmailAddress = $EmailAddress
        $orgAdminUser.Password = $Pasword
        $orgAdminUser.IsEnabled = $Enabled

        $vcloud = $DefaultCIServers[0].ExtensionData

        ## Find Role
        $orgAdminRole = $vcloud.RoleReferences.RoleReference | Where-Object {$_.Name -eq "Organization Administrator"}
        $orgAdminUser.Role = $orgAdminRole

        ## Create User
        $user = $orgED.CreateUser($orgAdminUser)

        Get-CIUser -Org $Org -Name $Name | Format-Table -AutoSize
    }
}

vCloud Director Customer Provisioning - Org User

Create VMware vCloud Director Organization VDC

Als letzter und umfangreichster Schritt soll der Kunde noch ein Virtual Datacenter (VDC) bekommen. Das Organization VDC (OrgVDC) legt grob gesagt die Compute, Storage und Netzwerk Ressourcen für den Mandanten fest.

Speziell die Storage Ressourcen gestalten sich in der Anlage ziemlich komplex wenn man mit Storage Profiles arbeitet. Weder das native Cmdlet zur Anlage eins neuen OrgVDC (New-OrgVdc) noch das Cmdlet zum Anpassen dieser (Set-OrgVdc) kennen Storage Profiles. Mit dem korrekten Storage Profil kann dann auch ein Privater Katalog für Medien und vApp Templates in der Organisation erstellt werden. Diesen Schritt könnte der Kunde zwar auch selbst erledigen, aber wenn wir ja sowieso schon dabei sind…

Note:

Das Provider VDC muss das Storage Profile ‚Any‚ aktiviert haben um das Provisionieren zu ermöglichen.
Dieses wird dann temporär dem neuen OrgVDC zugeordnet aber dann direkt gegen das korrekte ersetzt.

Aber auch im bereich Netzwerk gibt es einige Hürden zu nehmen. VXLAN Network Pools und External Networks sind auch nicht gerade simpel bereitzustellen.

Da es sich ja um ein standardisiertes Bereitstellen handelt werden auch wieder einige Optionen fix gesetzt.

Fixe Optionen:

  • Allocation Model
  • Network Quota
  • VM Quota
  • ‚vCpu In Mhz‘
  • Fast Provisioning
  • Thin Provisioning

Meine Funktion zum Bereitstellen eines Org VDC für das vCloud Director Customer Provisioning sieht dann so aus:

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function New-MyOrgVdc {
<#
.SYNOPSIS
    Creates a new vCD Org VDC with Default Parameters

.DESCRIPTION
    Creates a new vCD Org VDC with Default Parameters

    Default Parameters are:
    * Allocation Model
    * Network Quota
    * VM Quota
    * 'vCpu In Mhz'
    * Fast Provisioning
    * Thin Provisioning
    * private Catalog

.NOTES
    File Name  : New-MyOrgVdc.ps1
    Author     : Markus Kraus
    Version    : 1.2
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    New-MyOrgVdc -Name "TestVdc" -CPULimit 1000 -MEMLimit 1000 -StorageLimit 1000 -StorageProfile "Standard-DC01" -NetworkPool "NetworkPool-DC01" -ProviderVDC "Provider-VDC-DC01" -Org "TestOrg" -ExternalNetwork "External_OrgVdcNet"

.EXAMPLE
    New-MyOrgVdc -Name "TestVdc" -CPULimit 1000 -MEMLimit 1000 -StorageLimit 1000 -StorageProfile "Standard-DC01" -NetworkPool "NetworkPool-DC01" -ProviderVDC "Provider-VDC-DC01" -Org "TestOrg"

.PARAMETER Name
    Name of the New Org VDC as String

.PARAMETER CPULimit
    CPU Limit (MHz) of the New Org VDC as String

.PARAMETER MEMLimit
    Memory Limit (MB) of the New Org VDC as String

.PARAMETER StorageLimit
    Storage Limit (MB) of the New Org VDC as String

.PARAMETER StorageProfile
     Storage Profile of the New Org VDC as String

.PARAMETER NetworkPool
     Network Pool of the New Org VDC as String

.PARAMETER ExternalNetwork
     Optional External Network of the New Org VDC as String

.PARAMETER Enabled
    Should the New Org VDC be enabled after creation

    Default:$false

    Note: If an External Network is requested the Org VDC will be enabled during External Network Configuration

.PARAMETER ProviderVDC
    ProviderVDC where the new Org VDC should be created as string

.PARAMETER Org
    Org where the new Org VDC should be created as string

.PARAMETER Timeout
    Timeout for teh Org VDC to get Ready

    Default: 120s

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $Name,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="CPU Limit (MHz) of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [int] $CPULimit,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Memory Limit (MB) of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [int] $MEMLimit,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Storage Limit (MB) of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [int] $StorageLimit,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Storage Profile of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $StorageProfile,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Network Pool of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $NetworkPool,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Optional External Network of the New Org VDC as String")]
        [ValidateNotNullorEmpty()]
            [String] $ExternalNetwork,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the New Org VDC be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="ProviderVDC where the new Org VDC should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $ProviderVDC,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Org VDC should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $Org,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False,HelpMessage="Timeout for teh Org VDC to get Ready")]
        [ValidateNotNullorEmpty()]
            [int] $Timeout = 120
    )
    Process {
        ## Create Objects and all Settings
        Write-Verbose "Create Objects and all Settings"
        $adminVdc = New-Object VMware.VimAutomation.Cloud.Views.AdminVdc
        $adminVdc.Name = $name
        $adminVdc.IsEnabled = $Enabled
        $OrgVdcproviderVdc = Get-ProviderVdc $ProviderVDC
        $providerVdcRef = New-Object VMware.VimAutomation.Cloud.Views.Reference
        $providerVdcRef.Href = $OrgVdcproviderVdc.Href
        $adminVdc.ProviderVdcReference = $providerVdcRef
        $adminVdc.AllocationModel = "AllocationPool"
        $adminVdc.ComputeCapacity = New-Object VMware.VimAutomation.Cloud.Views.ComputeCapacity
        $adminVdc.ComputeCapacity.Cpu = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
        $adminVdc.ComputeCapacity.Cpu.Units = "MHz"
        $adminVdc.ComputeCapacity.Cpu.Limit = $CPULimit
        $adminVdc.ComputeCapacity.Cpu.Allocated = $CPULimit
        $adminVdc.ComputeCapacity.Memory = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
        $adminVdc.ComputeCapacity.Memory.Units = "MB"
        $adminVdc.ComputeCapacity.Memory.Limit = $MEMLimit
        $adminVdc.ComputeCapacity.Memory.Allocated = $MEMLimit
        $adminVdc.StorageCapacity = New-Object VMware.VimAutomation.Cloud.Views.CapacityWithUsage
        $adminVdc.StorageCapacity.Units = "MB"
        $adminVdc.StorageCapacity.Limit = $StorageLimit
        $adminVdc.NetworkQuota = 10
        $adminVdc.VmQuota = 0
        $adminVdc.VCpuInMhz = 1000
        $adminVdc.VCpuInMhz2 = 1000
        $adminVdc.UsesFastProvisioning = $false
        $adminVdc.IsThinProvision = $true

        ## Create Org vDC
        Write-Verbose "Create Org vDC"
        $OrgED = (Get-Org $Org).ExtensionData
        $orgVdc = $orgED.CreateVdc($adminVdc)

        ## Wait for getting Ready
        Write-Verbose "Wait for getting Ready"
        $i = 0
        while(($orgVdc = Get-OrgVdc -Name $Name).Status -eq "NotReady"){
            $i++
            Start-Sleep 2
            if($i -gt $Timeout) { Write-Error "Creating Org Failed."; break}
            Write-Progress -Activity "Creating Org" -Status "Wait for Org to become Ready..."
            }
        Write-Progress -Activity "Creating Org" -Completed
        Start-Sleep 2

        ## Search given Storage Profile
        Write-Verbose "Search given Storage Profile"
        $ProVdcStorageProfile = search-cloud -QueryType ProviderVdcStorageProfile -Name $StorageProfile | Get-CIView

        ## Create Storage Profile Object with Settings
        Write-Verbose "Create Storage Profile Object with Settings"
        $spParams = new-object VMware.VimAutomation.Cloud.Views.VdcStorageProfileParams
        $spParams.Limit = $StorageLimit
        $spParams.Units = "MB"
        $spParams.ProviderVdcStorageProfile = $ProVdcStorageProfile.href
        $spParams.Enabled = $true
        $spParams.Default = $true
        $UpdateParams = new-object VMware.VimAutomation.Cloud.Views.UpdateVdcStorageProfiles
        $UpdateParams.AddStorageProfile = $spParams

        ## Update Org vDC
        $orgVdc = Get-OrgVdc -Name $name
        $orgVdc.ExtensionData.CreateVdcStorageProfile($UpdateParams)

        ## Wait for getting Ready
        Write-Verbose "Wait for getting Ready"
        while(($orgVdc = Get-OrgVdc -Name $name).Status -eq "NotReady"){
            $i++
            Start-Sleep 1
            if($i -gt $Timeout) { Write-Error "Update Org Failed."; break}
            Write-Progress -Activity "Updating Org" -Status "Wait for Org to become Ready..."
            }
        Write-Progress -Activity "Updating Org" -Completed
        Start-Sleep 1

        ## Search Any-StorageProfile
        Write-Verbose "Search Any-StorageProfile"
        $orgvDCAnyProfile = search-cloud -querytype AdminOrgVdcStorageProfile | Where-Object {($_.Name -match '\*') -and ($_.VdcName -eq $orgVdc.Name)} | Get-CIView

        ## Disable Any-StorageProfile
        Write-Verbose "Disable Any-StorageProfile"
        $orgvDCAnyProfile.Enabled = $False
        $return = $orgvDCAnyProfile.UpdateServerData()

        ## Remove Any-StorageProfile
        Write-Verbose "Remove Any-StorageProfile"
        $ProfileUpdateParams = new-object VMware.VimAutomation.Cloud.Views.UpdateVdcStorageProfiles
        $ProfileUpdateParams.RemoveStorageProfile = $orgvDCAnyProfile.href
        $remove = $orgvdc.extensiondata.CreatevDCStorageProfile($ProfileUpdateParams)

         ## Wait for getting Ready
        Write-Verbose "Wait for getting Ready"
        while(($orgVdc = Get-OrgVdc -Name $name).Status -eq "NotReady"){
            $i++
            Start-Sleep 1
            if($i -gt $Timeout) { Write-Error "Update Org Failed."; break}
            Write-Progress -Activity "Updating Org" -Status "Wait for Org to become Ready..."
            }
        Write-Progress -Activity "Updating Org" -Completed
        Start-Sleep 1

        ## Set NetworkPool for correct location
        Write-Verbose "Set NetworkPool for correct location"
        $orgVdc = Get-OrgVdc -Name $name
        $ProVdcNetworkPool = Get-NetworkPool -ProviderVdc $ProviderVDC -Name $NetworkPool
        $set = Set-OrgVdc -OrgVdc $orgVdc -NetworkPool $ProVdcNetworkPool -NetworkMaxCount "10"

        ## Create private Catalog
        Write-Verbose "Create private Catalog Object"
        $OrgCatalog = New-Object VMware.VimAutomation.Cloud.Views.AdminCatalog
        $OrgCatalog.name = "$Org Private Catalog"
        if (!(Get-Org $org | Get-Catalog -Name $OrgCatalog.name -ErrorAction SilentlyContinue)) {
            Write-Verbose "Create private Catalog"
            $CreateCatalog = (Get-Org $org  | Get-CIView).CreateCatalog($OrgCatalog)
            $AccessControlRule = New-CIAccessControlRule -Entity $CreateCatalog.name -EveryoneInOrg -AccessLevel ReadWrite -Confirm:$False
            }
            else {
            Write-Output "Catalog '$($OrgCatalog.name)' aleady exists!"
                }

        ## Create a direct connect network
        if ($ExternalNetwork) {
            Write-Verbose "Create a direct connect network"
            Write-Output "Org VDC '$Name' needs to be enabled to add an external Network!"
            $EnableOrgVdc = Set-OrgVdc -OrgVdc $Name -Enabled:$True
            $orgVdcView = Get-OrgVdc $Name | Get-CIView
            $extNetwork = $_.externalnetwork
            $extNetwork = Get-ExternalNetwork | Get-CIView | Where-Object {$_.name -eq $ExternalNetwork}
            $orgNetwork = new-object vmware.vimautomation.cloud.views.orgvdcnetwork
            $orgNetwork.name = $ExternalNetwork
            $orgNetwork.Configuration = New-Object VMware.VimAutomation.Cloud.Views.NetworkConfiguration
            $orgNetwork.Configuration.FenceMode = 'bridged'
            $orgNetwork.configuration.ParentNetwork = New-Object vmware.vimautomation.cloud.views.reference
            $orgNetwork.configuration.ParentNetwork.href = $extNetwork.href

            $result = $orgVdcView.CreateNetwork($orgNetwork)
            }

        Get-OrgVdc -Name $name | Format-Table -AutoSize
    }
}

vCloud Director Customer Provisioning - Org VDC

vCloud Director Customer Provisioning - Catalog

Starten des vCloud Director Customer Provisioning

Um nun die oben aufgeführten Schritte alle mögliches effizient in Kombination auszuführen habe ich mir eine übergeordnete Funktion erstellt. Diese PowerShell Funktion wird mit einem JSON Config File gefüttert und ruft dann die erforderlichen Funktionen mit den entsprechenden Parametern auf.

In dieser übergeordneten Funktion habe ich zusätzlich die Möglichkeit abgebildet mit OrgVDC T-Shirt Sizes zu arbeiten. Das bedeutet hinter der Größe M ist dann bereits ein gewisse Parametrisierung für CPU RAM und Storage hinterlegt. Wenn in dem JSON File das Feld ‚FixedSize‘ leer ist („FixedSize“: „“,) werden die darauffolgenden, manuellen Werte verwendet.

Ähnliches gilt für das Feld ‚ExternalNetwork‘. Ist dieses leer wir das neue OrgVDC ohne ein Externes Netzwerk angelegt.

Das JSON Config File

{
"Org": {
        "Name":"TestOrg",
        "FullName": "Test Org",
        "Description":"Automation Test Org"
    },
"OrgAdmin": {
        "Name":"TestOrgAdmin",
        "Pasword": "myPassword1!",
        "FullName":"Test OrgAdmin",
        "EmailAddress":"test@admin.org"
    },
"OrgVdc": {
        "Name":"TestOrgVdc",
        "FixedSize": "M",
        "CPULimit": "1000",
        "MEMLimit":"1024",
        "StorageLimit":"1024",
        "StorageProfile":"Standard-DC01",
        "ProviderVDC":"Provider-VDC-DC01",
        "NetworkPool":"Provider-VDC-DC01-NetPool",
        "ExternalNetwork": "External-OrgVdcNet"
    }
}

Die PowerShell Funktion

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function Invoke-MyOnBoarding {
<#
.SYNOPSIS
    Creates all vCD Objecst for a new IAAS Customer

.DESCRIPTION
    Creates all vCD Objects for a new IAAS Customer

    All Objects are:
    * Org
    * Default Org Admin
    * Org VDC
    ** Private Catalog
    ** Optional Bridged Network

    JSON Config Example:

    {
    "Org": {
            "Name":"TestOrg",
            "FullName": "Test Org",
            "Description":"Automation Test Org"
        },
    "OrgAdmin": {
            "Name":"TestOrgAdmin",
            "Pasword": "myPassword1!",
            "FullName":"Test OrgAdmin",
            "EmailAddress":"test@admin.org"
        },
    "OrgVdc": {
            "Name":"TestOrgVdc",
            "FixedSize": "M",
            "CPULimit": "1000",
            "MEMLimit":"1000",
            "StorageLimit":"1000",
            "StorageProfile":"Standard-DC01",
            "ProviderVDC":"Provider-VDC-DC01",
            "NetworkPool":"Provider-VDC-DC01-NetPool",
            "ExternalNetwork": "External_OrgVdcNet"
        }
    }

.NOTES
    File Name  : Invoke-MyOnBoarding.ps1
    Author     : Markus Kraus
    Version    : 1.2
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    Invoke-MyOnBoarding -ConfigFile ".\OnBoarding.json" -Enabled:$true

.EXAMPLE
    Invoke-MyOnBoarding -ConfigFile ".\OnBoarding.json" -Enabled:$false

.PARAMETER ConfigFile
    Full Path to the JSON Config File

.PARAMETER Enabled
    Should the Customer be enabled after creation

    Default: $False

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Full Path to the JSON Config File")]
        [ValidateNotNullorEmpty()]
            [String] $ConfigFile,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False, HelpMessage="Should the Customer be enabled after creation")]
        [ValidateNotNullorEmpty()]
            [Switch]$Enabled
    )
    Process {

    $Valid = $true

    Write-Verbose "## Import JSON Config"
    Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config...`n"
    $Configs = Get-Content -Raw -Path $ConfigFile -ErrorAction Continue | ConvertFrom-Json -ErrorAction Continue

    if (!($Configs)) {
        $Valid = $false
        Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config Failed" -ForegroundColor Red
        }
        else {
            Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Importing JSON Config OK" -ForegroundColor Green
            }

    if ($Valid) {
        try{
            Write-Verbose "## Create Org"
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org...`n" -ForegroundColor Yellow
            $Trash = New-MyOrg -Name $Configs.Org.Name -FullName $Configs.Org.Fullname -Description $Configs.Org.Description -Enabled:$Enabled
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org OK" -ForegroundColor Green
            Get-Org -Name $Configs.Org.Name | Select-Object Name, FullName, Enabled | Format-Table -AutoSize
            }
            catch {
                $Valid = $false
                Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new Org Failed" -ForegroundColor Red
            }
        }

    if ($Valid) {
        try{
            Write-Verbose "## Create OrgAdmin"
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin...`n" -ForegroundColor Yellow
            $Trash = New-MyOrgAdmin -Name $Configs.OrgAdmin.Name -Pasword $Configs.OrgAdmin.Pasword -FullName $Configs.OrgAdmin.FullName  -EmailAddress $Configs.OrgAdmin.EmailAddress -Org $Configs.Org.Name -Enabled:$Enabled
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin OK" -ForegroundColor Green
            Get-CIUser -Org $Configs.Org.Name -Name $Configs.OrgAdmin.Name  | Select-Object Name, FullName, Email | Format-Table -AutoSize
            }
            catch {
                $Valid = $false
                Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgAdmin Failed" -ForegroundColor Red
            }
        }
    if ($Valid) {
        try{
            Write-Verbose "## Create OrgVdc"
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc...`n" -ForegroundColor Yellow

            if ($Configs.OrgVdc.FixedSize){

                Write-Host "Fixed Size (T-Shirt Size) '$($Configs.OrgVdc.FixedSize)' Org VDC Requested!"

                switch ($Configs.OrgVdc.FixedSize) {
                    M {
                        [String]$CPULimit = 36000
                        [String]$MEMLimit = 122880
                        [String]$StorageLimit = 1048576
                    }
                    L {
                        [String]$CPULimit = 36000
                        [String]$MEMLimit = 245760
                        [String]$StorageLimit = 1048576
                    }
                    default {throw "Invalid T-Shirt Size!"}
                    }

                }
                else{
                Write-Host "Custom Org VDC Size Requested!"

                $CPULimit = $Configs.OrgVdc.CPULimit
                $MEMLimit = $Configs.OrgVdc.MEMLimit
                $StorageLimit = $Configs.OrgVdc.StorageLimit

                }

            if ($Configs.OrgVdc.ExternalNetwork){
                $Trash = New-MyOrgVdc -Name $Configs.OrgVdc.Name -CPULimit $CPULimit -MEMLimit $MEMLimit -StorageLimit $StorageLimit -Networkpool $Configs.OrgVdc.NetworkPool -StorageProfile $Configs.OrgVdc.StorageProfile -ProviderVDC $Configs.OrgVdc.ProviderVDC -ExternalNetwork $Configs.OrgVdc.ExternalNetwork  -Org $Configs.Org.Name -Enabled:$Enabled
                }
                else {
                    $Trash = New-MyOrgVdc -Name $Configs.OrgVdc.Name -CPULimit $CPULimit -MEMLimit $MEMLimit -StorageLimit $StorageLimit -Networkpool $Configs.OrgVdc.NetworkPool -StorageProfile $Configs.OrgVdc.StorageProfile -ProviderVDC $Configs.OrgVdc.ProviderVDC -Org $Configs.Org.Name -Enabled:$Enabled
                }
            Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc OK" -ForegroundColor Green
            Get-OrgVdc -Org $Configs.Org.Name -Name $Configs.OrgVdc.Name  | Select-Object Name, Enabled, CpuAllocationGhz, MemoryLimitGB, StorageLimitGB, AllocationModel, ThinProvisioned, UseFastProvisioning, `
            @{N="StorageProfile";E={$_.ExtensionData.VdcStorageProfiles.VdcStorageProfile.Name}}, `
            @{N='VCpuInMhz';E={$_.ExtensionData.VCpuInMhz}} | Format-Table -AutoSize
            }
            catch {
                $Valid = $false
                Write-Host  "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") Creating new OrgVdc Failed" -ForegroundColor Red
            }
        }

    Write-Output "Overall Execution was Valid: $Valid"
    }
}

Offene Punkte vCloud Director Customer Provisioning

Wie dem aufmerksamen Leser vielleicht aufgefallen ist, kann die New-MyOrgVdc Funktion zwar auf Wunsch ein Externel Netzwerk im Bridged Modus dem OrgVDC hinzufügen aber ’noch‘ kein Edge Gatway.

Ich arbeite hier weiter an einer Möglichkeit. Wer da bereits etwas Vergleichbares in PowerShell abgebildet hat kann mir gerne eine Tipp geben. Auf meine VMware Community Frage gab es leider bisher keine Reaktionen.

Später soll das vCloud Director Customer Provisioning Modul dann über das blanke Anlegen hinaus erweitert werden. Also Erweitern der Ressourcen eines OrgVDC, hinzufügen weiterer Storage Profiles und weitere Dinge dieser Art.

Das vCloud Director Customer Provisioning Projekt

Pester Tests

Für mein Projekt habe ich auch ein paar grundlegende Pester Tests vorgesehen. Die Tests validieren die PowerShell Syntax, die Voranforderungen auf dem System und den erfolgreichen Import des Modules.

vCloud Director Customer Provisioning - Pester Tests

Read the Docs

Um den Einstieg in das vCloud Director Customer Provisioning etwas zu erleichtern habe ich, wie in meinem Plaster Artikel angekündigt, eine kleine Dokumentation der Funktionen bereitgestellt:

Welcome to my VMware-vCD-Module Module

vCloud Director Customer Provisioning - Read The Docs

GitHub Repository

Ein GitHub Repository durfte natürlich auch wieder nicht fehlen:

GitHub: VMware-vCD-Module

vCloud Director Customer Provisioning - GitHub Repository

Weitere Quellen

#LongLiveVCD

The post PowerCLI vCloud Director Customer Provisioning appeared first on my cloud-(r)evolution.

Flattr this!

PowerCLI – Create vCloud Director Edge Gateway

$
0
0

Bereits in meinem vorherigen Artikel habe ich gezeigt wie große Teile des Kunden OnBoarding im VMware vCloud Director mit PowerCLI Automatisiert werden können. Dabei ist auch ein PowerShell Modul entstanden, welches ich nun noch um einen weiteren Schritt ergänzt habe: Create vCloud Director Edge Gateway.

Vielen Dank an dieser Stelle auch  gleich an mavelite für sein tolles Beispiel in meinem VMware Community Beitrag.

Create vCloud Director Edge Gateway - Cmdlet

Create vCloud Director Edge Gateway – Anforderungen

Meine PowerShell Funktion soll im ersten Schritt nur eine Basis Konfiguration bereitstellen und eine standardisierte Konfiguration sicherstellen.

Rahmenbedingungen:

  • Ein Externes Netz am Edge Gateway
  • Eine Sub Allocation IP Range
  • Kein internes Netzwerk (Organisations Netzwerk) angebunden
  • HA nicht aktiviert
  • Größe des Edge Gateay ist Fix „klein“ bzw. „compact“

Die Limitierungen bei dem Schritt Create vCloud Director Edge Gateway sind erst einmal kein Problem, da die Funktion ja wieder Teil des Gesamtprojekts vCloud Director Customer Provisioning ist und der Funktionsumfang in diesem Zusammenhang absolut ausreichend ist.

Einbindung in vCloud Director Customer Provisioning

Um das vCloud Director Edge Gateway Provisioning in das bestehende Projekt einzubinden war nur eine Erweiterung des Config File und eine kleine Anpassung der Übergeordneten Funktion notwendig. Alle bestehenden Schritte blieben unverändert.

Neues Config File:

{
"Org": {
        "Name":"TestOrg",
        "FullName": "Test Org",
        "Description":"Automation Test Org"
    },
"OrgAdmin": {
        "Name":"TestOrgAdmin",
        "Pasword": "myPassword1!",
        "FullName":"Test OrgAdmin",
        "EmailAddress":"test@admin.org"
    },
"OrgVdc": {
        "Name":"TestOrgVdc",
        "FixedSize": "M",
        "CPULimit": "1000",
        "MEMLimit":"1024",
        "StorageLimit":"1024",
        "StorageProfile":"Standard-DC01",
        "ProviderVDC":"Provider-VDC-DC01",
        "NetworkPool":"Provider-VDC-DC01-NetPool",
        "ExternalNetwork": "External-OrgVdcNet",
        "EdgeGateway": "Yes",
        "IPAddress":"192.168.100.1",
        "SubnetMask":"255.255.255.0",
        "Gateway":"192.168.100.254",
        "IPRangeStart":"192.168.100.2",
        "IPRangeEnd":"192.168.100.3"
    }
}

[-] Object, 3 properties
Org
[-] Object, 3 properties
Name TestOrg
FullName Test Org
Description Automation Test Org
OrgAdmin
[-] Object, 4 properties
Name TestOrgAdmin
Pasword myPassword1!
FullName Test OrgAdmin
EmailAddress test@admin.org
OrgVdc
[-] Object, 15 properties
Name TestOrgVdc
FixedSize M
CPULimit 1000
MEMLimit 1024
StorageLimit 1024
StorageProfile Standard-DC01
ProviderVDC Provider-VDC-DC01
NetworkPool Provider-VDC-DC01-NetPool
ExternalNetwork External-OrgVdcNet
EdgeGateway Yes
IPAddress 192.168.100.1
SubnetMask 255.255.255.0
Gateway 192.168.100.254
IPRangeStart 192.168.100.2
IPRangeEnd 192.168.100.3

Powered by: http://chris.photobooks.com/json/default.htm

Neuer Aufruf:

vCloud Director Edge Gateway Provisioning integration

Create vCloud Director Edge Gateway – Script

#Requires -Version 4
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.3.0.0"}
Function New-MyEdgeGateway {
<#
.SYNOPSIS
    Creates a new Edge Gateway with Default Parameters

.DESCRIPTION
    Creates a new Edge Gateway with Default Parameters

    Default Parameters are:
    * Size
    * HA State
    * DNS Relay


.NOTES
    File Name  : New-MyEdgeGateway.ps1
    Author     : Markus Kraus
    Version    : 1.0
    State      : Ready

.LINK
    https://mycloudrevolution.com/

.EXAMPLE
    New-MyEdgeGateway -Name "TestEdge" -OrgVDCName "TestVDC" -OrgName "TestOrg" -ExternalNetwork "ExternalNetwork" -IPAddress "192.168.100.1" -SubnetMask "255.255.255.0" -Gateway "192.168.100.254" -IPRangeStart ""192.168.100.2" -IPRangeEnd ""192.168.100.3" -Verbose

.PARAMETER Name
    Name of the New Edge Gateway as String

.PARAMETER OrgVDCName
    OrgVDC where the new Edge Gateway should be created as string

.PARAMETER OrgName
    Org where the new Edge Gateway should be created as string

.PARAMETER ExternalNetwork
     External Network of the new Edge Gateway as String

.PARAMETER IPAddress
     IP Address of the New Edge Gateway as IP Address

.PARAMETER SubnetMask
     Subnet Mask of the New Edge Gateway as IP Address

.PARAMETER Gateway
     Gateway of the New Edge Gateway as IP Address

.PARAMETER IPRangeStart
     Sub Allocation IP Range Start of the New Edge Gateway as IP Address

.PARAMETER IPRangeEnd
     Sub Allocation IP Range End of the New Edge Gateway as IP Address

.PARAMETER Timeout
    Timeout for the Edge Gateway to get Ready

    Default: 120s

#>
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Name of the New Edge Gateway as String")]
        [ValidateNotNullorEmpty()]
            [String] $Name,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="OrgVDC where the new Edge Gateway should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $OrgVdcName,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Org where the new Edge Gateway should be created as string")]
        [ValidateNotNullorEmpty()]
            [String] $OrgName,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="External Network of the New Edge Gateway as String")]
        [ValidateNotNullorEmpty()]
            [String] $ExternalNetwork,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="IP Address of the New Edge Gateway as IP Address")]
        [ValidateNotNullorEmpty()]
            [IPAddress] $IPAddress,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Subnet Mask of the New Edge Gateway as IP Address")]
        [ValidateNotNullorEmpty()]
            [IPAddress] $SubnetMask,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Gateway of the New Edge Gateway as IP Address")]
        [ValidateNotNullorEmpty()]
            [IPAddress] $Gateway,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Sub Allocation IP Range Start the New Edge Gateway as IP Address")]
        [ValidateNotNullorEmpty()]
            [IPAddress] $IPRangeStart,
        [Parameter(Mandatory=$True, ValueFromPipeline=$False, HelpMessage="Sub Allocation IP Range End the New Edge Gateway as IP Address")]
        [ValidateNotNullorEmpty()]
            [IPAddress] $IPRangeEnd,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False,HelpMessage="Timeout for the Edge Gateway to get Ready")]
        [ValidateNotNullorEmpty()]
            [int] $Timeout = 120
    )
    Process {

    ## Get Org vDC
    Write-Verbose "Get Org vDC"
    [Array] $orgVdc = Get-Org -Name $OrgName | Get-OrgVdc -Name $OrgVdcName

    if ( $orgVdc.Count -gt 1) {
        throw "Multiple OrgVdcs found!"
        }
        elseif ( $orgVdc.Count -lt 1) {
            throw "No OrgVdc found!"
            }
    ## Get External Network
    Write-Verbose "Get External Network"
    $extNetwork = Get-ExternalNetwork | Get-CIView -Verbose:$False | Where-Object {$_.name -eq $ExternalNetwork}

    ## Build EdgeGatway Configuration
    Write-Verbose "Build EdgeGatway Configuration"
    $EdgeGateway = New-Object VMware.VimAutomation.Cloud.Views.Gateway
    $EdgeGateway.Name = $Name
    $EdgeGateway.Configuration = New-Object VMware.VimAutomation.Cloud.Views.GatewayConfiguration
    #$EdgeGateway.Configuration.BackwardCompatibilityMode = $false
    $EdgeGateway.Configuration.GatewayBackingConfig = "compact"
    $EdgeGateway.Configuration.UseDefaultRouteForDnsRelay = $false
    $EdgeGateway.Configuration.HaEnabled = $false

    $EdgeGateway.Configuration.EdgeGatewayServiceConfiguration = New-Object VMware.VimAutomation.Cloud.Views.GatewayFeatures
    $EdgeGateway.Configuration.GatewayInterfaces = New-Object VMware.VimAutomation.Cloud.Views.GatewayInterfaces

    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface = New-Object VMware.VimAutomation.Cloud.Views.GatewayInterface
    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].name = $extNetwork.Name
    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].DisplayName = $extNetwork.Name
    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].Network = $extNetwork.Href
    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].InterfaceType = "uplink"
    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].UseForDefaultRoute = $true
    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].ApplyRateLimit = $false

    $ExNetexternalSubnet = New-Object VMware.VimAutomation.Cloud.Views.SubnetParticipation
    $ExNetexternalSubnet.Gateway = $Gateway.IPAddressToString
    $ExNetexternalSubnet.Netmask = $SubnetMask.IPAddressToString
    $ExNetexternalSubnet.IpAddress = $IPAddress.IPAddressToString
    $ExNetexternalSubnet.IpRanges = New-Object VMware.VimAutomation.Cloud.Views.IpRanges
    $ExNetexternalSubnet.IpRanges.IpRange = New-Object VMware.VimAutomation.Cloud.Views.IpRange
    $ExNetexternalSubnet.IpRanges.IpRange[0].StartAddress = $IPRangeStart.IPAddressToString
    $ExNetexternalSubnet.IpRanges.IpRange[0].EndAddress =   $IPRangeEnd.IPAddressToString

    $EdgeGateway.Configuration.GatewayInterfaces.GatewayInterface[0].SubnetParticipation = $ExNetexternalSubnet

    ## Create EdgeGatway
    Write-Verbose "Create EdgeGatway"
    $CreateEdgeGateway = $orgVdc.ExtensionData.CreateEdgeGateway($EdgeGateway)

    ## Wait for EdgeGatway to become Ready
    Write-Verbose "Wait for EdgeGatway to become Ready"
    while((Search-Cloud -QueryType EdgeGateway -Name $Name -Verbose:$False).IsBusy -eq $True){
        $i++
        Start-Sleep 5
        if($i -gt $Timeout) { Write-Error "Creating Edge Gateway."; break}
        Write-Progress -Activity "Creating Edge Gateway" -Status "Wait for Edge to become Ready..."
    }
    Write-Progress -Activity "Creating Edge Gateway" -Completed
    Start-Sleep 1

    Search-Cloud -QueryType EdgeGateway -Name $Name | Select-Object Name, IsBusy, GatewayStatus, HaStatus | Format-Table -AutoSize


    }
}

Tipp:

Bei der Entwicklung war das Show-Object Skript von Lee Holmes aus seinem Windows PowerShell Cookbook extrem hilfreich. Damit konnte ich sehr schnell alle gewünschten Werte bei einem bestehenden Edge Gateway entnehmen und auch die einzelnen Objekt Typen überprüfen.

#LongLiveVCD

The post PowerCLI – Create vCloud Director Edge Gateway appeared first on my cloud-(r)evolution.

Flattr this!

Veeam Availability Suite Unattended Install

$
0
0

Um mein Lab bei Bedarf wieder schnell aufzubauen habe ich mir vorgenommen alle Installationen, soweit möglich, zu automatisieren. Da nun auch wieder ein Veeam Backup & Replication 9.5 Server mit Veeam Enterprise Manager zu meinem Lab gehören soll, war mein erstes PowerShell Projekt der Veeam Availability Suite Unattended Install.

Natürlich habe ich mich als erstes umgesehen, ob sich nicht bereits jemand Anderes die Arbeit gemacht hat. Und tatsächlich, das Projekt von Timothy Dewin ist sogar in dem Veeam PowerShell GitHub Repository zur Verfügung gestellt (95_simple_auto_install_all.ps1). Dieses Skript sieht schon mehr als ordentlich aus, ich konnte es aber natürlich dennoch nicht lassen es noch etwas zu überarbeiten.

Veeam Availability Suite Unattended Install - Console

Veeam Availability Suite Unattended Install

Zusätzlich zur reinen Installation der Veeam Availability Suite 9.5 hab ich mir auch angesehen wie man einige der grundlegenden Konfigurationen automatisieren könnte, z.B. VMware vCenter oder NetApp ONTAP Filer in Veeam Backup & Replication 9.5 aufnehmen. Daher ist der Artikel auch in zwei Teilabschnitte gegliedert.

Abschnitte:

Veeam Availability Suite Unattended Install im Detail

Wie bereits erwähnt habe ich mir als Basis das Skript von Timothy Dewin genommen und dieses etwas verfeinert. Wichtig war für mich unter anderem die Kontrolle der MSI Logs auf eine erfolgreiche Installation. Dazu suche ich ganz simple in dem Log nach dem String für eine fehlerfreie Installation „Installation success or error status: 0„.

Beispiel:

if (Select-String -path "$logdir\02_Shared.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

Die Anlage des lokalen Users für die Veeam Prozesse und die SQL Verbindung habe ich anders als beim dem originalen Skript mit dem in PowerShell 5.1 neu eingeführten Cmdlet New-LocalUser erledigt. Nachteil ist natürlich, dass man diese PowerShell Version installiert haben muss.

Alle notwendigen MSI Parameter für die einzelnen Veeam Komponenten können dem Veeam Unattended Installation Guide entnommen werden.

Unattended Install Skript

Um das Veeam Availability Suite Unattended Install Skript erfolgreich auszuführen, müssen ein paar Voranforderungen erfüllt werden:

  • PowerShell 5.1 ist installiert und neu gestartet
  • .Net 4.5.2 ist installiert und neu gestartet
  • Veeam Availability Suite 9.5 Update 2 ISO ist eingelegt
  • Administrator Rechte sind vorhanden

Für die beiden zusätzlichen Software Pakete habe ich die Installationsroutinen auch in das Skript eingefügt aber auskommentiert. Um PowerShell 5.1 zu installieren muss das Windows Management Framework 5.1 heruntergeladen werden, .Net 4.5.2 ist auf dem Veeam Availability Suite 9.5 Update 2 ISO zu finden.

# Requires PowerShell 5.1
# Requires .Net 4.5.2 and Reboot

#region: Variables
$source = "F:"
$licensefile = "C:\_install\veeam_availability_suite_trial_32_0.lic"
$username = "svc_veeam"
$fulluser = $env:COMPUTERNAME+ "\" + $username
$password = "Passw0rd!"
$CatalogPath = "D:\VbrCatalog"
$vPowerPath = "D:\vPowerNfs"
#endregion

#region: logdir
$logdir = "C:\logdir"
$trash = New-Item -ItemType Directory -path $logdir  -ErrorAction SilentlyContinue
#endregion

### Optional .Net 4.5.2
<#
Write-Host "    Installing .Net 4.5.2 ..." -ForegroundColor Yellow
$Arguments = "/quiet /norestart"
Start-Process "$source\Redistr\NDP452-KB2901907-x86-x64-AllOS-ENU.exe" -ArgumentList $Arguments -Wait -NoNewWindow
Restart-Computer -Confirm:$true
#>

### Optional PowerShell 5.1
<#
Write-Host "    Installing PowerShell 5.1 ..." -ForegroundColor Yellow
$Arguments = "C:\_install\Win8.1AndW2K12R2-KB3191564-x64.msu /quiet /norestart"
Start-Process "wusa.exe" -ArgumentList $Arguments -Wait -NoNewWindow
Restart-Computer -Confirm:$true
#>

#region: create local admin
Write-Host "Creating local user '$fulluser' with password '$password' ..." -ForegroundColor Yellow
$trash = New-LocalUser -Name $username -Password ($password | ConvertTo-SecureString -AsPlainText -Force) -Description "Service Account for Veeam" -AccountNeverExpires -ErrorAction Stop
Add-LocalGroupMember -Group "Administrators" -Member $username -ErrorAction Stop
#endregion

#region: Installation
#  Info: https://www.veeam.com/unattended_installation_ds.pdf

## Global Prerequirements
Write-Host "Installing Global Prerequirements ..." -ForegroundColor Yellow
### 2012 System CLR Types
Write-Host "    Installing 2012 System CLR Types ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Redistr\x64\SQLSysClrTypes.msi"
    "/qn"
    "/norestart"
    "/L*v"
    "$logdir\01_CLR.txt"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\01_CLR.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### 2012 Shared management objects
Write-Host "    Installing 2012 Shared management objects ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Redistr\x64\SharedManagementObjects.msi"
    "/qn"
    "/norestart"
    "/L*v"
    "$logdir\02_Shared.txt"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\02_Shared.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### SQL Express
### Info: https://msdn.microsoft.com/en-us/library/ms144259.aspx
Write-Host "    Installing SQL Express ..." -ForegroundColor Yellow
$Arguments = "/HIDECONSOLE /Q /IACCEPTSQLSERVERLICENSETERMS /ACTION=install /FEATURES=SQLEngine,SNAC_SDK /INSTANCENAME=VEEAMSQL2012 /SQLSVCACCOUNT=`"NT AUTHORITY\SYSTEM`" /SQLSYSADMINACCOUNTS=`"$fulluser`" `"Builtin\Administrators`" /TCPENABLED=1 /NPENABLED=1 /UpdateEnabled=0"
Start-Process "$source\Redistr\x64\SQLEXPR_x64_ENU.exe" -ArgumentList $Arguments -Wait -NoNewWindow

## Veeam Backup & Replication
Write-Host "Installing Veeam Backup & Replication ..." -ForegroundColor Yellow
### Backup Catalog
Write-Host "    Installing Backup Catalog ..." -ForegroundColor Yellow
$trash = New-Item -ItemType Directory -path $CatalogPath -ErrorAction SilentlyContinue
$MSIArguments = @(
    "/i"
    "$source\Catalog\VeeamBackupCatalog64.msi"
    "/qn"
    "/L*v"
    "$logdir\04_Catalog.txt"
    "VM_CATALOGPATH=$CatalogPath"
    "VBRC_SERVICE_USER=$fulluser"
    "VBRC_SERVICE_PASSWORD=$password"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\04_Catalog.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### Backup Server
Write-Host "    Installing Backup Server ..." -ForegroundColor Yellow
$trash = New-Item -ItemType Directory -path $vPowerPath -ErrorAction SilentlyContinue
$MSIArguments = @(
    "/i"
    "$source\Backup\Server.x64.msi"
    "/qn"
    "/L*v"
    "$logdir\05_Backup.txt"
    "ACCEPTEULA=YES"
    "VBR_LICENSE_FILE=$licensefile"
    "VBR_SERVICE_USER=$fulluser"
    "VBR_SERVICE_PASSWORD=$password"
    "PF_AD_NFSDATASTORE=$vPowerPath"
    "VBR_SQLSERVER_SERVER=$env:COMPUTERNAME\VEEAMSQL2012"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\05_Backup.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### Backup Console
Write-Host "    Installing Backup Console ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Backup\Shell.x64.msi"
    "/qn"
    "/L*v"
    "$logdir\06_Console.txt"
    "ACCEPTEULA=YES"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\06_Console.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### Explorers
Write-Host "    Installing Explorer For ActiveDirectory ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Explorers\VeeamExplorerForActiveDirectory.msi"
    "/qn"
    "/L*v"
    "$logdir\07_ExplorerForActiveDirectory.txt"
    "ACCEPTEULA=YES"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\07_ExplorerForActiveDirectory.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

Write-Host "    Installing Explorer For Exchange ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Explorers\VeeamExplorerForExchange.msi"
    "/qn"
    "/L*v"
    "$logdir\08_VeeamExplorerForExchange.txt"
    "ACCEPTEULA=YES"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\08_VeeamExplorerForExchange.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

Write-Host "    Installing Explorer For SQL ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Explorers\VeeamExplorerForSQL.msi"
    "/qn"
    "/L*v"
    "$logdir\09_VeeamExplorerForSQL.txt"
    "ACCEPTEULA=YES"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\09_VeeamExplorerForSQL.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

Write-Host "    Installing Explorer For Oracle ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Explorers\VeeamExplorerForOracle.msi"
    "/qn"
    "/L*v"
    "$logdir\10_VeeamExplorerForOracle.txt"
    "ACCEPTEULA=YES"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\10_VeeamExplorerForOracle.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

Write-Host "    Installing Explorer For SharePoint ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\Explorers\VeeamExplorerForSharePoint.msi"
    "/qn"
    "/L*v"
    "$logdir\11_VeeamExplorerForSharePoint.txt"
    "ACCEPTEULA=YES"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\11_VeeamExplorerForSharePoint.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

## Enterprise Manager
Write-Host "Installing Enterprise Manager ..." -ForegroundColor Yellow
### Enterprise Manager Prereqirements
Write-Host "    Installing Enterprise Manager Prereqirements ..." -ForegroundColor Yellow
$trash = Install-WindowsFeature Web-Default-Doc,Web-Dir-Browsing,Web-Http-Errors,Web-Static-Content,Web-Windows-Auth -Restart:$false -WarningAction SilentlyContinue
$trash = Install-WindowsFeature Web-Http-Logging,Web-Stat-Compression,Web-Filtering,Web-Net-Ext45,Web-Asp-Net45,Web-ISAPI-Ext,Web-ISAPI-Filter,Web-Mgmt-Console -Restart:$false  -WarningAction SilentlyContinue

$MSIArguments = @(
    "/i"
    "$source\Redistr\x64\rewrite_amd64.msi"
    "/qn"
    "/norestart"
    "/L*v"
    "$logdir\12_Rewrite.txt"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\12_Rewrite.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### Enterprise Manager Web
Write-Host "    Installing Enterprise Manager Web ..." -ForegroundColor Yellow
$MSIArguments = @(
    "/i"
    "$source\EnterpriseManager\BackupWeb_x64.msi"
    "/qn"
    "/L*v"
    "$logdir\13_EntWeb.txt"
    "ACCEPTEULA=YES"
    "VBREM_LICENSE_FILE=$licensefile"
    "VBREM_SERVICE_USER=$fulluser"
    "VBREM_SERVICE_PASSWORD=$password"
    "VBREM_SQLSERVER_SERVER=$env:COMPUTERNAME\VEEAMSQL2012"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow

if (Select-String -path "$logdir\13_EntWeb.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### Enterprise Manager Cloud Portal
Write-Host "    Installing Enterprise Manager Cloud Portal ..." -ForegroundColor Yellow
<#
$MSIArguments = @(
    "/i"
    "$source\Cloud Portal\BackupCloudPortal_x64.msi"
    "/L*v"
    "$logdir\14_EntCloudPortal.txt"
    "/qn"
    "ACCEPTEULA=YES"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow
#>
Start-Process "msiexec.exe" -ArgumentList "/i `"$source\Cloud Portal\BackupCloudPortal_x64.msi`" /l*v $logdir\14_EntCloudPortal.txt /qn ACCEPTEULA=`"YES`"" -Wait -NoNewWindow

if (Select-String -path "$logdir\14_EntCloudPortal.txt" -pattern "Installation success or error status: 0.") {
    Write-Host "    Setup OK" -ForegroundColor Green
    }
    else {
        throw "Setup Failed"
        }

### Update 2
Write-Host "Installing Update 2 ..." -ForegroundColor Yellow
$Arguments = "/silent /noreboot /log $logdir\15_update.txt VBR_AUTO_UPGRADE=1"
Start-Process "$source\Updates\veeam_backup_9.5.0.1038.update2_setup.exe" -ArgumentList $Arguments -Wait -NoNewWindow
#endregion

Das Skript ist auch GitHub Gist zur Verfügung gestellt.

Vorsicht:

Der letzte Schritt in dem Veeam Availability Suite Unattended Install PowerShell Skript ist die Installation des Update 2. Dieses befindet sich erst seit kurzem mit auf dem ISO!

Weitere Konfigurationen

Neben dem reinen Veeam Availability Suite Unattended Install sind zusätzlich grundlegende Konfigurationen an der frischen Installation denkbar.

Zusätzliche Konfigurationen:

  • vCenter hinzufügen
  • NetApp Filer hinzufügen
  • Backup Server in Enterprise Manager aufnehmen

vCenter zu Veeam Backup Server hinzufügen

Für diese Konfiguration muss das mit der Konsole zusammen installierte Veeam PowerShell PSSnapIn genutzt werden, und zwar konkret das Add-VBRvCenter Cmdlet. Wie der Veeam PowerShell Reference zu entnehmen ist, kann hierfür ein User mit Passwort mitgegeben werden oder auf bestehende Credentials zugegriffen werden. Ich mache in meinem Beispiel ersteres.

if (Get-PSSnapin -Registered -Name VeeamPSSnapIn -ErrorAction SilentlyContinue) {
    Add-PSSnapin -Name VeeamPSSnapIn
    }

Disconnect-VBRServer -ErrorAction SilentlyContinue
Connect-VBRServer -Server Veeam-01.lab.local

if (Get-VBRServer) {
    Add-VBRvCenter -Name "192.168.3.101" -Description "Lab vCenter" -User "Administrator@vSphere.local" -Password "Passw0rd!" -Verbose
    }

NetApp Filer zu Veeam Backup Server hinzufügen

Für das Add-NetAppHost Cmdlet gilt das gleiche wie im vorherigen Schritt mit dem vCenter, Details sind der Veeam PowerShell Reference zu entnehmen.

if (Get-PSSnapin -Registered -Name VeeamPSSnapIn -ErrorAction SilentlyContinue) {
    Add-PSSnapin -Name VeeamPSSnapIn
    }

Disconnect-VBRServer -ErrorAction SilentlyContinue
Connect-VBRServer -Server Veeam-01.lab.local

if (Get-VBRServer) {
    Add-NetAppHost -Name "192.168.3.103" -Description "Lab NetApp" -UserName "admin" -Password "Anfang!!11"
    }

Veeam Backup Server zu Enterprise Manager hinzufügen

Für diese Konfiguration muss auf die Veeam Backup Enterprise Manager RESTful API zugegriffen werden, daher ist das Skript leider auch entsprechend komplexer.

Es sing vier REST Calls notwendig:

  1. Authentifizieren
  2. Server hinzufügen
  3. Server ID abrufen (optional)
  4. Server Collection (optional)

Die Collection ist optional, da der „default schedule“ für die Collection ohnehin alle 15 Minuten läuft.

[String] $Server = "192.168.3.100"
[Boolean] $HTTPS = $True
[String] $Port = "9398"
[String] $Authentication = "<dummy>"

#region: Workaround for SelfSigned Cert
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
#endregion

#region: Switch Http/s
if ($HTTPS -eq $True) {$Proto = "https"} else {$Proto = "http"}
#endregion

#region: POST - Authorization
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/sessionMngr/?v=v1_2"
Write-Verbose "Authorization Url: $URL"
$Auth = @{uri = $URL;
                   Method = 'POST';
                   Headers = @{Authorization = 'Basic ' + $Authentication;
           }
   }
try {$AuthXML = Invoke-WebRequest @Auth -ErrorAction Stop} catch {Write-Error "`nERROR: Authorization Failed!";Exit 1}
#endregion

#region: POST - Add BR Server
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/backupServers?action=create"
Write-Verbose "Add BR Server Url: $URL"
$BRServer = @{uri = $URL;
                   Method = 'POST';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId'];
                                'Content-Type' = 'application/xml'}
                   Body = '
                   <BackupServerSpec xmlns="http://www.veeam.com/ent/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                     <Description>Veeam Lab Server</Description>
                     <DnsNameOrIpAddress>192.168.3.100</DnsNameOrIpAddress>
                     <Port>9392</Port>
                     <Username>Veeam-01\svc_veeam</Username>
                     <Password>Passw0rd!</Password>
                    </BackupServerSpec>
                    '
           } 
	
try {$BRServerXML = Invoke-RestMethod @BRServer -ErrorAction Stop} catch {Write-Error "`nERROR: Add BR Server Failed!";Exit 1}
#endregion

#region: GET - Get BR Server
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/backupServers"
Write-Verbose "Get BR Server Url: $URL"
$BRServer = @{uri = $URL;
                   Method = 'GET';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId']}
           } 
	
try {$BRServerXML = Invoke-RestMethod @BRServer -ErrorAction Stop} catch {Write-Error "`nERROR: Get BR Server Failed!";Exit 1}

#endregion

#region: POST - Collect BR Server
[String] $URL = $BRServerXML.EntityReferences.Ref.Href + "?action=collect"
Write-Verbose "Collect BR Server Url: $URL"
$BRServer = @{uri = $URL;
                   Method = 'POST';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId']}
           } 
	
try {$BRServerXML = Invoke-RestMethod @BRServer -ErrorAction Stop} catch {Write-Error "`nERROR: Collect BR Server Failed!";Exit 1}
#endregion

 

The post Veeam Availability Suite Unattended Install appeared first on my cloud-(r)evolution.

Flattr this!

vCloud Director PowerCLI Ressource Usage Report

$
0
0

Um einen schnellen Überblick über relevante Kennzahlen in einer VMware vCloud Director Infrastruktur zu erhalten, gibt das Produkt leider nicht so viele Information an einer zentralen Stelle her wie ich mir das wüschen würde. Zur internen Verwendung, habe ich mir daher einen Ressource Usage Report mit VMware PowerCLI erstellt.
Für die Erfassung der Daten nutze ich das vCloud Director und das vRealize Operations Manager PowerShell Modul von VMware PowerCLI. Die Verwendung der vRealize Operations Manager Daten in meinem Report ist momentan eine Spielerei um zu evaluieren, ob man das eventuell weiter ausbauen kann und damit auf Daten direkt aus dem vCloud Director komplett verzichten könnte. Bisher habe ich aber noch keine Lösung für die benötigten Edge Gateay Informationen gefunden.

Zur Darstellung des Reports habe ich mich primär für eine HTML Seite entschieden. Diese habe ich mit Hilfe des PowerShell Moduls aus dem Artikel PowerShell: Daten als HTML Report ausgeben auch ganz übersichtlich hinbekommen. Alternativ kann der Export aber auch als CSV erfolgen, was die Weiterverarbeitung der Daten natürlich erleichtern soll.

PowerCLI Ressource Usage Report

Dieses kleine Projekt zeigt übrigens ganz nebenbei wie mächtig PowerShell sein kann, wenn man verschiedene PowerShell Module in der Kombination verwendet. Hier vCloud Director und vRealize Operations Manager.

Ressource Usage Report im Detail

Folgende Werte habe ich in der ersten Version des Reports zusammengeführt:

Org Name der Organisation
OrgVdc Name des VDC
OmHealth VDC Health Badge aus dem vROps
CpuUsed Aktuelle CPU Nutzung
RamUsed Aktuelle RAM Nutzung
VApps Anzahl der vApps
VAppTemplates Anzahl der vApp Templates
VMs Anzahl der VMs
VMsOff Anzahl ausgeschalteter VMs
StorageProfile Liste der Storage Profil
StorageLimit Zugewiesener Storage pro Profil
StorageUsed Genutzter Storage
EdgeGateway Name des Edge Gateway in angegebenen Netz
Ip IP des Edge Gateway
IpRangeCount Anzahl zusätzliche IPs des Edge Gateway

Die PowerShell Funktion Get-vCDReport auf meinem PowerShell Modul hat als Konsolen Ausgabe nur den Pfad des Exports.

Edge Gateway Daten

Hinter der Ausgabe der Edge Gateway Daten steht der Gedanke, dass es ein bestimmtes externes Netz gibt, welches besonders erfasst werden muss. Zum Beispiel weil in diesem Netz öffentliche Adressen vergeben werden.

Daher kann dem Cmdlet mit dem Parameter -NetworkName diese Netz mitgegeben werden. Mit Hilfe einer etwas abgewandelten Funktion aus meinem Artikel vCloud Director Edge-Gateway IP Report werden die IPs und der Name des Edge Gateway in diesem Netz für den Report erfasst.

Theoretisch ist diese Funktion auch unabhängig von dem Report nutzbar:

$EdgeView = Search-Cloud -QueryType EdgeGateway | Get-CIView
Get-EdgeReport -EdgeView $EdgeView | Format-Table -Autosize

Aufruf Ressource Usage Report

Um das Modul zu verwenden müssen ein paar vorbereitende Schritte durchgeführt werden:

  1. VMware PowerCLI Module Importieren (Download – Version 6.5.1)
  2. VMware-vCD-Report Modul Importieren (Download – Version 1.0)
  3. VMware vCloud Director verbinden (Connect-CIServer)
  4. (optional) VMware vRealize Operations Manager verbinden (Connect-OMServer)

# Import VMware Modules
Get-Module -ListAvailable -Name VMware* | Import-Module
# Import my VMware-vCD-Report Module
Import-Module ".\VMware-vCD-Report\PEC-vCD-Report.psm1"
# Connect vCD
Connect-CIServer <Your Server>
# Connect vROps
Connect-OMServer <Your Server>

Der Report kann nun mit der Funktion Get-vCDReport als HTML erzeugt werden:

Get-vCDReport -NetworkName "MyExternalNetwork" -OutputFilePath "C:\Temp\" -OMMetrics:$True -OutputType "HTML"

Soll die Ausgabe als CSV erfolgen:

Get-vCDReport -NetworkName "MyExternalNetwork" -OutputFilePath "C:\Temp\" -OMMetrics:$True -OutputType "CSV"

Falls keine VMware vRealize Operations Manager Daten gesammelt werden sollen:

Get-vCDReport -NetworkName "MyExternalNetwork" -OutputFilePath "C:\Temp\" -OMMetrics:$False

Ressource Usage Report Code

Ich beschränke mich hier auf die beiden exportierten Funktionen des PowerShell Moduls. Zusätzlich habe ich mich aber zweier anderer Funktionen aus der Community bedient:

Das komplette Modul aus dem Beitrag ist meinem GitHub Repository VMware-vCD-Report zu finden.

Get-vCDReport

Die Haupt-Funktion des Moduls.

Function Get-vCDReport{
<# 
    .SYNOPSIS  
    Creates the HTML or CSV Output of VMware vCloud Director Ressources.

     .EXAMPLE 
    Get-vCDReport -NetworkName "MyExternalNetwork" -OutputFilePath "C:\Temp\" -OMMetrics:$True -OutputType "HTML"

#> 
  Param (
        [Parameter(Mandatory=$False, ValueFromPipeline=$False)]
        [ValidateNotNullorEmpty()]
           [String]$NetworkName = "NONE",
        [Parameter(Mandatory=$False, ValueFromPipeline=$False)]
        [ValidateNotNullorEmpty()]
           [String]$OutputFilePath = ".\",
        [Parameter(Mandatory=$False, ValueFromPipeline=$False)]
        [ValidateNotNullorEmpty()]
           [Switch]$OMMetrics = $true,
        [Parameter(Mandatory=$False, ValueFromPipeline=$False)]
        [ValidateNotNullorEmpty()]
        [ValidateSet("CSV","HTML")]
            [String]$OutputType = "HTML"
        )


$OrgViews = Search-Cloud -QueryType Organization | Get-CIView -Verbose:$false
if ($OMMetrics) {
    $OmHealthStati = Get-OMResource -ResourceKind ORG_VDC
}

$Report = @()
foreach ($OrgView in $OrgViews) {
    foreach ($OrgVdc in $OrgView.Vdcs.Vdc){
    $obj = "" | Select-Object Org, OrgVdc, OmHealth, "CpuUsed(GHz)", "RamUsed(GB)", VApps, VAppTemplates, VMs, VMsOff, `
    StorageProfiles, "StorageLimit(GB)", "StorageUsed(GB)", EdgeGateway, Ip, IpRangeCount
    $obj.Org = $OrgView.Name
    $obj.OrgVdc = $OrgVdc.Name
    if ($OMMetrics) {
        try {
            $obj.OmHealth = ($OmHealthStati | Where-Object {$_.Name -eq $OrgVdc.Name} ).Health    
        }
        catch {
            $obj.OrgVdc = "N/A"    
        }   
    }
    else {
        $obj.OrgVdc = "N/A"    
    }
        $OrgVdc = Search-Cloud -QueryType AdminOrgVdc -Name $OrgVdc.Name
        $OrgVdcView = $OrgVdc | Get-CIView -Verbose:$false
    #$obj."CpuAllocated(GHz)" = [Math]::Round(($OrgVdcView.ComputeCapacity.Cpu.Allocated / 1000), 2)
    $obj."CpuUsed(GHz)" = [Math]::Round(($OrgVdcView.ComputeCapacity.Cpu.Used / 1000), 2)
    #$obj."RamAllocated(GB)" = [Math]::Round(($OrgVdcView.ComputeCapacity.Memory.Allocated / 1024), 2)
    $obj."RamUsed(GB)" = [Math]::Round(($OrgVdcView.ComputeCapacity.Memory.Used / 1024), 2)
    $obj.VApps = $OrgVdc.NumberOfVApps
    $obj.VAppTemplates = $OrgVdc.NumberOfVAppTemplates
        [Array]$OrgVdcVMs = Search-Cloud -QueryType AdminVM -Filter "Vdc==$($OrgVDC.Id)"
    if ($OrgVdcVMs) {
      $obj.VMs = $OrgVdcVMs.Count
      [Array]$OrgVdcVMsOff = $OrgVdcVMs | where {$_.Status -eq "POWERED_OFF"}
      if ($OrgVdcVMsOff) {
        $obj.VMsOff = $OrgVdcVMsOff.Count   
      }
      else {
          $obj.VMsOff = 0  
      }
              
    }
    else{
        $obj.VMs = 0 
        $obj.VMsOff = 0    
    }

        [Array]$OrgVdcStorageView = Search-Cloud -QueryType AdminOrgVdcStorageProfile -Filter "VdcName==$($OrgVdc.Name)"
    $obj.StorageProfiles = $OrgVdcStorageView.Name -join ", "
        $StorageLimit = @()
        foreach ($StorageObject in $OrgVdcStorageView.StorageLimitMB) {
            $StorageLimit += [Math]::Round(($StorageObject / 1024), 2)    
        }
    $obj."StorageLimit(GB)" = $StorageLimit -join ", " 
        $StorageUsed = @()
        foreach ($StorageObject in $OrgVdcStorageView.StorageUsedMB) {
            $StorageUsed += [Math]::Round(($StorageObject / 1024), 2)    
        }
    $obj."StorageUsed(GB)" = $StorageUsed -join ", " 

        $EdgeView = Search-Cloud -QueryType EdgeGateway -Filter "Vdc==$($OrgVdcView.Id)" | Get-CIView
    if ($EdgeView) {
            $VcdEdgeReport = Get-EdgeReport -EdgeView $EdgeView | Where-Object {$_.NetworkName -like $NetworkName}
        if ($VcdEdgeReport) {
            $obj.EdgeGateway = $VcdEdgeReport.EdgeName
            $obj.Ip = $VcdEdgeReport.IP
            $obj.IpRangeCount = $VcdEdgeReport.IPRangeCount
        }
    }

    $Report += $obj 
    }    
}

if ($OutputType -eq "HTML") {
   $OutputFileName = $OutputFilePath + "HtmlReport.html"
   $InputObject =  @{Object = $Report}
   $trash = Export-HtmlReport -InputObject $InputObject -ReportTitle "vCD Ressource Usage Report" -OutputFileName $OutputFileName
}
elseif ($OutputType -eq "CSV") {
    $OutputFileName = $OutputFilePath + "CsvReport.csv"
    $Report | Export-Csv -Path $OutputFileName -Delimiter ";"       
}
"Output File: '$OutputFileName'`n"
}

Get-EdgeReport

Eigentlich nur eine Sub-Funktion aber so nützlich, dass ich die doch exportiert habe.

Function Get-EdgeReport{
<# 
    .SYNOPSIS  
    Creates a Report of Edge Gateway Details. 

    .EXAMPLE 
    $EdgeView = Search-Cloud -QueryType EdgeGateway | Get-CIView
    Get-EdgeReport -EdgeView $EdgeView | Format-Table -Autosize

#> 
    Param (
        [Parameter(Mandatory=$True, ValueFromPipeline=$False)]
        [ValidateNotNullorEmpty()]
            $EdgeView
        )


    $EdgeReport = @()
    foreach ($Edge in $EdgeView) {

        [Array]$GatewayInterfaces = $Edge.Configuration.GatewayInterfaces
        foreach($GatewayInterface in $GatewayInterfaces.GatewayInterface){ 
            $obj = "" | Select-Object EdgeName, NetworkName, IP, IPRangeCount            
            $obj.EdgeName = $Edge.Name
            $obj.NetworkName = $GatewayInterface.Name
            $obj.IP = $GatewayInterface.SubnetParticipation.IpAddress
            [Array] $RangeReport = @()
            if ($GatewayInterface.SubnetParticipation.IpRanges){
                foreach ($IPRange in $GatewayInterface.SubnetParticipation.IpRanges.IpRange) {
                    [Array] $Range = Get-IPrange -start $IPRange.StartAddress -end $IPRange.EndAddress
                    foreach($IP in $Range){  
                        $RangeReport += $IP
                        }
                    }
                }
            $obj.IPRangeCount = $RangeReport.Count 
            $EdgeReport += $obj     
            }
                    
                
        }

    $EdgeReport
    }

#LongLiveVCD

The post vCloud Director PowerCLI Ressource Usage Report appeared first on my cloud-(r)evolution.

Flattr this!

NetApp Data ONTAP Simulator in vCloud Director

$
0
0

NetApp stellt den Simulator für NetApp Filer zwar als VMware Appliance zur Verfügung, leider klappt aber der Import in VMware vCloud Director nicht mit dem bereitgestellten File. In diesem Artikel werde ich aufzeigen wie man dennoch den NetApp Data ONTAP Simulator in vCloud Director erfolgreich importieren kann ohne den Umweg über das VMware vCenter zu machen.

Vorbereitung:

NetApp Data ONTAP Simulator in vCloud Director - Download

NetApp Data ONTAP Simulator konvertieren

Um den NetApp Data ONTAP Simulator in vCloud Director zu nutzen, müssen wir das bereitgestellte OVA zu einem OVF konvertieren. Hierzu verwendet man am einfachste das VMware OVF Tool:

ovftool.exe C:\temp\vsim-esx-DOT9.1-cm.ova C:\temp\OVF\vsim-esx-DOT9.1-cm.ovf

NetApp Data ONTAP Simulator in vCloud Director - Convert

Aus dem angegebenen OVA File wird eine neue OVF Struktur erzeugt:

NetApp Data ONTAP Simulator in vCloud Director - OVF

NetApp Data ONTAP Simulator hochladen

Das neu erzeugte OVF kann dann ohne Probleme in dem VMware vCloud Director hochgeladen werden. Hierzu kann entweder das Client Integration Plugin für das VMware vCloud Director WebPortal oder Ebenfalls das VMware OVF Tool genutzt werden.

Beispiel für den Upload mit dem VMware OVF Tool:

ovftool.exe "C:\temp\OVF\vsim-esx-DOT9.1-cm\vsim-esx-DOT9.1-cm.ovf" "vcloud://<USER>:@<URL>:443?org=<ORG>&vdc=<VDC>&catalog=<CATALOG>&vappTemplate=NetApp-SIM"

NetApp Data ONTAP Simulator in vCloud Director - Upload

Ist der NetApp Data ONTAP Simulator in vCloud Director hochgeladen, steht das neue vApp-Template im Katalog zur Verfügung:

NetApp Data ONTAP Simulator in vCloud Director - Catalog

NetApp Data ONTAP Simulator bereitstellen

Aus dem vApp-Template kann nun je nach Bedarf ein Single Node Cluster oder auch ein Normaler Cluster mit zwei Nodes bereitgestellt werden. Der Simulate ONTAP 9.0 Installation and Setup Guide ist auch genauso gültig für den NetApp Data ONTAP Simulator in vCloud Director.

Mein Design der vApp als Cluster mit zwei Nodes sieht so aus:

NetApp Data ONTAP Simulator in vCloud Director - vApp

  • Cluster Netzwerk als vApp Netzwerk ohne externe Anbindung
  • Cluster und Node Management Interfaces als Org Netzwerk

NetApp Data ONTAP Simulator in vCloud Director - vApp-Detail

Der grobe Ablauf für die Konfiguration des HA Clusters im Simulator sieht so aus:

  1. Ersten Node wipen
  2. Ersten Node mit neuem Cluster Konfigurieren
  3. Cluster License hinzufügen
  4. Zweiten Node SystemID und Seriennummer neu schreiben
  5. Zweiten Node wipen
  6. Zweiten Node neu Konfigurieren mit Cluster Join
  7. Weitere Lizenzen hinzufügen

Danach kann mit dem NetApp OnCommand System Manager auf das Cluster zugegriffen werden:

NetApp Data ONTAP Simulator in vCloud Director - NetApp OnCommand System Manager

Warum es so wichtig ist die SystemID und die Seriennummer des zweiten Nodes neu zu schreiben merkt man spätestens beim hinzufügen einer weiteren Lizenz. Wenn alles sauber funktioniert hat sollte es z.B. so aussehen:

NetApp Data ONTAP Simulator in vCloud Director - License

NetApp Data ONTAP Simulator 9.2

Leider gibt es aktuell den Simulator noch nicht in der neuen Data ONTAP Version 9.2. Wie das Upgrade durchgeführt werden kann zeigt der Artikel von Stefan Renner:

How to: Upgrade NetApp ONTAP Simulator 9.1 to 9.2

Kommende, verwandte Themen

In einem meiner nächsten Artikel werde ich aufzeigen wie man die NetApp OnCommand Unified Manager Appliance für die Verwendung in VMware vCloud Director anpasst. Soviel sei schon mal gesagt, das ist etwas aufwendiger…

The post NetApp Data ONTAP Simulator in vCloud Director appeared first on my cloud-(r)evolution.

Flattr this!


Veeam Self-Service Backup Portal for vCloud Director

$
0
0

Jeder Service Provider wird sehr schnell feststellen müssen, dass der Bedarf der Kunden bezüglich einer Datensicherung recht hoch ist (was ja auch eigentlich sehr gut ist – solange man das auch anbieten kann). Wer mit dem VMware vCloud Director und damit auf der VMware vSphere Plattform arbeitet kommt nicht um den Platzhirsch, Veeam Backup & Replication herum. Doch gerade Service Provider müssen massiv auf Self-Service setzen, einerseits um Kosten zu sparen und andererseits um den Kunden die gewünschte Flexibilität zu gewähren. Hierfür bietet die Veeam Availablitiy Suite das Veeam Self-Service Backup Portal, welches auch mit dem VMware vCloud Director hervorragend  zusammenspielt.

Ein enorm wichtiges Kriterium ist für mich, dass der Kunde sich auch an dem neuen Portal mit seinen bereits bekannten Credentials anmelden kann und nicht noch weitere bekommt. Wie dieser Artikel von Luca Dell’Oca beschreibt sogar per LDAP: Use vCloud Director LDAP authentication with Veeam self-service portal

Veeam Self-Service Backup Portal – Aufbau

Der notwendigen Komponenten der Veeam Infrastruktur sind für Kenner der Veeam Availablity Suite nichts Neues. Einzig der Veeam Enterprise Manager wird wohl nicht so sehr verbreitet sein.

Mein Test Aufbau:

  • Veeam Backup & Replication Server
    • SQL Express
  • Veeam Backup Repository
    • Windows Server mit zwei Disks für ein Scale-out Repository
    • NFS Mount Server
  • Veeam Backup Proxy
    • Windows Server für VMware Hot-Add (Virtual Appliance Mode)
  • Veeam Enterprise Manager
    • SQL Express

Da es sich hier um einen Test Aufbau handelt, habe ich etwas an Ressourcen gespart. Die folgenden Sizing Angaben sind ein Wunsch für den produktiven Einsatz und nicht ganz so umgesetzt in meinem Lab. Speziell im Service Provider Umfeld sollte jedoch das korrekte Sizing und das Augenmerk auf spätere Skalierung oberste Prämisse sein. Ein guter Start für weitere Infos ist der Veeam Best Practice Guide mit dem Abschnitt Sizing and System Requirements.

Veeam Backup & Replication Server

Basis Setup des Veeam Backup & Replication Server habe ich mit meinem Veeam Availability Suite Unattended Install Script durchgeführt (unter 30 Minuten!).

Mein Sizing (20 Jobs):

  • 4 vCPUs
  • 16 GB RAM

Veeam Backup Repository

Um die Nutzung eines Scale-out Repository zu simulieren habe ich einen Windows Server mit zwei Disks bereitgestellt. Auf jeder Disk habe ich ein Backup Repository angelegt und diese dann als Extends für mein Scale-out Repository genutzt.

Veeam Self-Service Backup Portal - Scale-Out Repository

Veeam Self-Service Backup Portal - Scale-Out Repository Details

Bei einer großen Anzahl von Veeam Backup Proxys wird das Repository sehr schnell zum Flaschenhals. Das Sizing sollte daher gut aufeinander abgestimmt sein.

Mein Sizing je Server (4 Tasks):

  • 4 vCPUs
  • 16 GB RAM

Konfiguration Scale-out Repository:

  • Data Locality Mode

Performance Tweak:

  • RSS auf der Netzwerkkarte aktivieren
  • Filesystem Block Size 64KB

Veeam Backup Proxy

Als Backup Proxy kommt für mich in der gegebenen Infrastruktur nur der Virtual Appliance Mode in Frage. Eine sehr gute Gegenüberstellung der möglichen Veeam Backup Transport Typen hat Andreas Lesslhumer in seinem Artikel Veeam backup transportation modes – all you need to know erstellt.

Ich habe zur maximalen Skalierung auf jedem ESXi Host im vCloud Director Provider VDC einen Windows System als Hot-Add Proxy bereitgestellt.

Mein Sizing je Server (2 Tasks):

  • 2 vCPUs
  • 4 GB RAM

Tweak:

  • Automount per Diskpart deaktivieren

Veeam Enterprise Manager

Der Einfachheit halber habe ich diesen mit meinem Veeam Availability Suite Unattended Install Script zusammen auf dem Veeam Backup & Replication Server installiert. Aus Gründen der Sicherheit im produktiven Umfeld ziemlich bedenklich. Aber dazu kommen wir später.

Mein Sizing:

  • 4 vCPUs
  • 8 GB RAM

Performance Tweak:

Veeam Self-Service Backup Portal – Sicherheit

Ich bin der Meinung, man kann die Komponenten in diesem Aufbau in mindestens drei Sicherheits-Zonen aufteilen.

  1. Zone für den Zugriff von außen (Rot)
  2. Zone für Management Systeme (Blau)
  3. Zone für Backup Daten (Orange)

Veeam Self-Service Backup Portal - Security Zones

Um die Umgebung und die Kundendaten zu schützen sollten für die rote und orange Zone sehr explizite Firewall Regeln gelten.

Die notwendigen Ports sind sehr übersichtlich im Veeam Best Practice Guide im dem Abschnitt Networking Diagrams dargestellt. Mehr Detail sind aber noch im User Guide for VMware vSphere zu finden.

Veeam Self-Service Backup Portal – Administration

Ich überspringe hier die Basis Konfiguration von Veeam Backup & Replication sowie Veeam Enterprise Manager.

Initial sind grundlegend folgende Schritte zu machen:

  1. Veeam Backup Repositories erstellen
  2. Veeam Backup Proxies hinzufügen
  3. vCenter hinzufügen
  4. vCloud Director hinzufügen
  5. Konfigurations Backup einrichten
  6. Backup Server im Enterprise Manager hinzufügen

Und damit kommen wir zu den Veeam Self-Service Backup Portal spezifischen Aufgaben.

 vCloud Org im Veeam Self-Service Backup Portal Berechtigen

Veeam Self-Service Backup Portal - vCloud Org

Organization:

Werden aus dem VMware vCloud Director eingelesen.

Repository:

Alle Repositories aus dem Veeam Backup Server stehen hier zur Verfügung.

Quota:

Kann frei vergeben werden. Dieses kann auch die tatsächliche Kapazität überschreiten!

Job Scheduling:

Mögliche Optionen:

  • Allow: Tenant has full access to all job scheduling options
  • Allow: Tenant can create daily and monthly jobs only
  • Deny: Creates daily jobs with randomized start time within the backup window
  • Deny: Creates job with no schedule assigned

Advanced Job Settings:

Hiermit können die Job Einstellung für den Tenant vorgegeben werden.

Veeam Self-Service Backup Portal - vCloud Org Job Template

Erzeugt werden die eigenen Vorlagen am besten durch deaktivierte Backup Jobs.

Automation

Natürlich wird so ein Prozess im Service Provider Umfeld automatisiert werden. Dazu ist die Veeam Backup Enterprise Manager RESTful API fester Bestandteil vom Veeam Enterprise Manager.

Wer sich noch nicht mit dieser API beschäftigt hat, findet einen guten Einstieg mit dem Artikel Consuming the Veeam REST API in PowerShell – Part 1 – Starting a job von Mike Preston. Ich habe schon in anderen Projekten mit dieser API gearbeitet, der vCloud Director Teil war jedoch neu für mich.

Mein Skript zur Veeam Enterprise Manager Organization Konfiguration:

Veeam Self-Service Backup Portal - vCloud Org PowerShell

Ich habe als Skriptsprache für die REST API Calls PowerShell gewählt (weil ich das am besten beherrsche), es kann aber natürlich auch in jeder anderen Sprache umgesetzt werden.

[String] $Server = "<Veeam Ent. Manager IP / name>"
[Boolean] $HTTPS = $True
[String] $Port = "9398"
[PSCredential] $Credential = Get-Credential
[String] $Org = "<Your vCloud Director Org>"
[String] $JobTemplateName = "<Your Job name>" 
[String] $RepoName = "<Your Repository name>" 
[Long] $Quota = 500

#region: Workaround for SelfSigned Cert
add-type @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(
            ServicePoint srvPoint, X509Certificate certificate,
            WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
#endregion

#region: Switch Http/s
if ($HTTPS -eq $True) {$Proto = "https"} else {$Proto = "http"}
#endregion

#region: POST - Authorization
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/sessionMngr/?v=latest"
Write-Verbose "Authorization Url: $URL"
$Auth = @{uri = $URL;
            Method = 'POST';
            }
$AuthXML = Invoke-WebRequest @Auth -ErrorAction Stop -Credential $Credential
#endregion


#region: GET - Get BR Server
"`nGet All Registered Veeam Server..."
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/backupServers?format=Entity"
Write-Verbose "Get BR Server Url: $URL"
$BRServer = @{uri = $URL;
                   Method = 'GET';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId']}
           } 
	
$BRServerXML = Invoke-RestMethod @BRServer -ErrorAction Stop

$BRServerXML.BackupServers.BackupServer | select Name, UID, Port, Version

$BRServerUID = $BRServerXML.BackupServers.BackupServer.UID
#endregion



#region: GET - Get BR Template Job
"`nGet all Backup Jobs to filter Template..."
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/jobs?format=Entity"
$BRJobs = @{uri = $URL;
                   Method = 'GET';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId']}
           } 
	
$BRJobsXML = Invoke-RestMethod @BRJobs -ErrorAction Stop

$BRJobsXML.Jobs.Job | select Name, UID, Platform | ft -AutoSize

foreach ($Job in $BRJobsXML.Jobs.job) {
    if ($job.name -eq $JobTemplateName) {$JobTemplateXML = $Job} 
}

$BRJobUID = $JobTemplateXML.uid
#endregion

#region: GET - Get BR Repo
"`nGet all Backup Repositories to filter Selected..."
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/repositories?format=Entity"
$BRRepos = @{uri = $URL;
                   Method = 'GET';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId']}
           } 
	
$BRReposXML = Invoke-RestMethod @BRRepos -ErrorAction Stop

$BRReposXML.Repositories.Repository | select Name, UID, Kind

foreach ($Repo in $BRReposXML.Repositories.Repository) {
    if ($Repo.name -eq $RepoName) {$RepoXML = $Repo} 
}

$BRRepoUID = $RepoXML.uid
#endregion

#region: POST - Add vCloud Org
"`nCreate vCloud Org..."
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/vCloud/orgConfigs"
$VCloudOrganizationConfigCreate = @{uri = $URL;
                   Method = 'POST';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId'];
                                'Content-Type' = 'application/xml'}
Body = @"
<VCloudOrganizationConfigCreateSpec xmlns="http://www.veeam.com/ent/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <OrganizationName>$org</OrganizationName>
    <BackupServerUid>$BRServerUID</BackupServerUid>
    <RepositoryUid>$BRRepoUID</RepositoryUid>
    <QuotaGb>$Quota</QuotaGb>
    <TemplateJobUid>$BRJobUID</TemplateJobUid>
    <JobSchedulerType>Full</JobSchedulerType>
</VCloudOrganizationConfigCreateSpec>
"@
           } 

	$VCloudOrganizationConfigCreateXML = Invoke-RestMethod @VCloudOrganizationConfigCreate -ErrorAction Stop
#endregion

#region: GET - Get vCloud Org
"`nGet all vCloud Org`s..."
[String] $URL = $Proto + "://" + $Server + ":" + $Port + "/api/vCloud/orgConfigs?format=Entity"
$VCloudOrganizationConfig = @{uri = $URL;
                   Method = 'GET';
				   Headers = @{'X-RestSvcSessionId' = $AuthXML.Headers['X-RestSvcSessionId']}
           } 
	
$VCloudOrganizationConfigXML = Invoke-RestMethod @VCloudOrganizationConfig -ErrorAction Stop

$VCloudOrganizationConfigXML.VCloudOrganizationConfigs.VCloudOrganizationConfig | select Name, UID, QuotaGb | ft -AutoSize
#endregion

Das Skript habe ich auch als GitHub Gist zur Verfügung gestellt.

Bestehende Backups

Wer bereits vor der Einführung des Self-Service Portals vCloud Director Backup Jobs direkt im Veeam Backup & Replication Server eingerichtet hatte, kann diese mit dem PowerShell Cmdlet Set-VBRvCloudOrganizationJobMapping für den Tenant im Portal verfügbar machen.

Veeam Self-Service Backup Portal – Tenant

Nachdem eine vCloud Director Organisation im Veeam Enterprise Manager berechtigt wurde können sich laut der Fehlermeldung im Portal alle User mit den Rechten ‚Administrator Control‘ und ‚Administrator View‘ anmelden.

Veeam Self-Service Backup Portal - Portal Failed Login

Leider scheint das so nicht ganz korrekt zu sein, ein vCloud Direktir vApp User mit diesen zusätzlichen Rechten kann sich immer noch nicht erfolgreich anmelden. Alle Organization Administrators können sich jedoch ohne Probleme anmelden und haben vollen Zugriff auf die Funktionen.

Ich hoffe ich kann zu dem Berechtigungsproblem bald noch mal ein Update zum Artikel hinzufügen. Wer mir einen Tipp geben kann, gerne einen Kommentar hinterlassen.

Zugriff der User erfolgt im Normalfall über folgende URL:

https://<Veeam Ent. Manager FQDN>:9443/vCloud/<vCloud Director Org Name>/

Um den Zugriff sicherer und zugleich komfortabler zu gestalten habe ich das Portal hinter einen Load-Balancer bzw. Reverse Proxy mit Web Application Firewall gesetzt (in meinem Lab KEMP Virtual LoadMaster). Der Zugriff erfolg in meinem Lab über die URL:

https://<FQDN>/vCloud/<vCloud Director Org Name>/

Den Veeam Enterprise Manager HTTP(S) Port permanent auf 443 im IIS umzustellen ist übrigens nicht empfehlenswert, jedes Update führt dann zu Problemen. Man kann aber alternativ 443 als zusätzlichen Port im IIS hinzufügen.

Übersicht

Als Startseite bietet das Veeam Self-Service Backup Portal dem Nutzer einen schnellen Überblick über seine letzten Backup Jobs und das zur Verfügung stehende Backup Storage.

Veeam Self-Service Backup Portal - User Dashboard

Backup Jobs überwachen

In der Ansicht der Backup Jobs kann zusätzlich zu der offensichtlichen Liste der vorhandenen Jobs noch tiefer in den letzten Lauf oder alle Läufe der Jobs hineingeklickt werden.

Veeam Self-Service Backup Portal - User Jobs

Bis hin zu den Logs der einzelnen Tasks:

Veeam Self-Service Backup Portal - User Task Logs

Backup Jobs erstellen

Der Tenant kann in dem Portal Backup Jobs für verschiedene VMware vCloud Director Objekt Typen erstellen:

  • vCloud Direktor Organisationen
  • vCloud Direktor virtual DataCenter
  • vCloud Direktor vApps
  • vCloud Direktor VMs

Je nach Typ werden dann natürlich auch die nachfolgenden Objekte gesichert (z.B. Bei einer vApp: Netzwerke, VM´s, etc.).

Hier eine Step-by-Step Diashow eines neuen Backup Jobs:

Anklicken um

Die erweiterten J0b Parameter und das Ziel Repository werden vom Provider vorgegeben (Siehe Abschnitt Administration).

VM Restore

Der VM Restore bei vCloud Director umfasst nicht nur VMs sondern auch ganze vApps. An einer vApp können noch weitere Objekte wie zum Beispiel Netzwerke oder Firewall Regeln hängen.

Meine Test vApp für den Restore Test hat all diese Objekte:

Veeam Self-Service Backup Portal - vCD vApp Diagram

Veeam Self-Service Backup Portal - vCD vApp Networking

Für diesen Test habe ich die komplette vApp gelöscht und den Restore über das Veeam Self-Service Backup Portal gestartet.

Veeam Self-Service Backup Portal - User Restore VM 1

Veeam Self-Service Backup Portal - User Restore VM 2

Der Restore Prozess kann dann über das Portal vom Tenant auch komplett überwacht werden:

Veeam Self-Service Backup Portal - User Restore VM 3

Nach dem erfolgreichen Restore ist die vApp mit allen VM´s und MetaDaten (Netzwerke, Firewall und NAT Regeln, vApp Einstellungen) wieder vollständig im vCloud Director vorhanden.

Genauso sauber hat der Restore ohne das Vorherige löschen der vApp funktioniert.

Es ist noch zu beachten, dass nach dem Restore der kompletten vApp vorherige SavePoints nicht mehr für einen VM Retsore in die originale Lokation zu verwenden sind. Die vApp wurde mit einer neuen ID neu erzeugt. Ein Restore an einen anderen Ort (vApp oder Storage Policy) ist über das Veeam Self-Service Backup Portal nicht vorgesehen.

File Restore

File Restores können für Windows und für die meisten Linux Derivate ebenfalls über das Veeam Self-Service Backup Portal durchgeführt werden. Mit der kleinen Einschränkung, dass ich den Tenants nur den Download der Files und nicht den direkten Restore in den Gast empfehlen würde. Für den Restore direkt in den Gast werden meist die Netzwerkanforderungen nicht erfüllt sein.

Veeam Self-Service Backup Portal - User Restore File

Um die Files von Linux VMs zu öffnen muss durch den Provider einmal der Wizard für die Multi-OS File Level Recovery Appliance auf dem Veeam Backup & Replication Server gestartet werden. Um auch hier möglichst skalierbar zu sein ist es zu empfehlen die Appliances nicht mit statischen IPs sondern über einen DHCP zu konfigurieren.

Dieser Hinweis ist ebenfalls im Veeam Best Practice Guide in dem Abschnitt Veeam vCloud Director Self-Service Portal zu finden.

Veeam Self-Service Backup Portal – Überwachung

Um die Backup und Restore Jobs der Kunden zentral im Blick zu haben kann ich aus eigener Erfahrung das Veeam Content Pack for VMware vRealize Log Insight sehr empfehlen.

Veeam Self-Service Backup Portal - Log Insight Dashboard

Mit ein paar weiteren Log Analysen kann man z.B. auch Anmeldung mit nicht ausrechend berechtigen Usern identifizieren:

Veeam Self-Service Backup Portal - Log Insight Logs

Veeam Self-Service Backup Portal – Verbesserungswünsche

Ich habe um meine Wünsche zu adressieren auch den Thread im Veeam Service Provider Forum eröffnet.

Tenant Funktionen

Als größtes Problem sehe ich aktuell die pauschale Zuordnung von Backup Job Funktionen an alle Tenants. Ich würde mir wünschen, dass der Provider festlegen kann ob der Tenant Guest processing nutzen darf oder nicht. Damit könnte dann auch der Reiter ITEMS für des Veeam Self-Service Backup Portal ein- und ausgeblendet werden (aktuell nur mit einem kleinen Trick möglich). Das gleiche Problem habe ich mit dem File Restore direkt in den Gast. Für beide Funktionen sind spezielle Netzwerkanforderungen notwendig, die meist nicht erfüllt werden. Daher sollte das immer optional sein.

Mehrere Backup Repositories

Ich würde mir wünschen, dass der Provider dem Tenant mehrere Repositories zuordnen kann. Damit könnte man mehrere Anforderungen erfüllen:

  • Verschiedene Performance Klasse
  • Verschiedene Standorte

Mehrere Standorte sind dann interessant, wenn ein Provider über eine vCloud Director Zelle mehrere VDC Lokationen anbieten möchte.

Logs

Die Logs, die der Tenant im Veeam Self-Service Backup Portal sehen kann sind mir entschieden zu detailliert. Ich denke nicht, dass Kunden sehen müssen warum der Job fehlgeschlagenen ist, wo das Bottleneck war oder welche Transport Methode verwendet wird.

Restore an andere Lokation

Bei der Recherche im Veeam Service Provider Forum bin ich noch auf eine andere, absolut korrekte Anforderung gestoßen. Ein anderer Nutzer möchte in eine andere Storage Policy wiederherstellen. Dieses würde ich sogar noch erweitern und zwar sollte eine einzelne VM auch in eine andere bzw. neue vApp wiederhergestellt werden können.

#LongLiveVCD

The post Veeam Self-Service Backup Portal for vCloud Director appeared first on my cloud-(r)evolution.

Flattr this!

VMware vCloud Director Upgrade 8.10 to 8.20

$
0
0

Mein aktuelles Projekt, VMware vCloud Director Upgrade 8.10 to 8.20, ist es aus zwei Gründen wert einen Artikel dazu zu verfassen. Zum einen sind die Neuerungen in VMware vCloud Director 8.20 wirklich großartig aber zum anderen läuft der Upgrade Prozess nicht ganz problemlos ab.

Zu den Neuerungen in VMware vCloud Director 8.20 wurden bereits so viele tolle Blog Artikel verfasst, dass ich eigentlich gar nichts Weiteres hinzufügen kann. Hier eine kleine Auswahl:

Für mich ist der große Treiber für das Update der Umgebung ganz klar die Distributed Firewall als Self-Service Funktion, aber auch so Kleinigkeiten wie die deutsche Eingabesprache in der VM Konsole oder die VM to ESXi Host Affinity Rules sind ein echter Mehrwert. Eine gute Zusammenfassung der Neuerungen ist im What’s New in VMware vCloud Director 8.20 White Paper zu finden.

Einen guten Einblick in die neuen Advanced Networking Features gibt auch dieses YouTube Video:

VMware vCloud Director Upgrade – Berechtigungen

Interessanter weise ist nicht der VMware vCloud Director Upgrade Prozess der Zellen oder der Datenbank an sich das Problem, diese laufen robust und sind ausreichend Dokumentiert (Natürlich hat auch Tom Fojta einen sehr guten Artikel dazu verfasst).

Die Komplikationen treten nach dem eigentlichen VMware vCloud Director Upgrade auf, bzw. können auftreten. Die Ursache dafür sind die automatisch freigeschalteten neuen Features in den Rollen der Organisations Administrationen. VMware hat das Konzept der Globalen Rollen für alle Organisationen mit der Version über Bord geworfen und generiert während dem Upgrade Prozess für jede Organisation eine eigene Rolle. Somit können die Rechte nun viel granularer zugewiesen werden. Mehr Details zu dem neuen Konzept: vCloud Director 8.20: Granular Role Based Access Control

An sich eine tolle Neuerung, wenn nicht allen Organisations Administrationen sofort das Recht Manage Firewall für die Freischaltung der Distributed Firewall bekommen würden. Noch fataler ist, dass das gleiche für das Recht Convert to Advanced Gateway zur Konvertierung eines Edge Gateways zum Advanced Gateway gilt. Führt ein Tenant Administrator direkt die Konvertierung seines Edge Gateway durch, kann der Tenant mit keinem seiner User in der neuen HTML5 UI die Dienste des Advanced Gateway verwalten. Die Rechte müssen erst durch den System Administrator (Provider) für Ihn freigeschaltet werden. Diese Freischaltung erfolg nicht automatisch während des VMware vCloud Director Upgrade Prozess. Zusätzlich sind in der UI diese Rechte auch nicht so einfach aktivierbar, dazu aber mehr weiter unten.

vCloud Director upgrade - Advanced Gateway Default

Ein System Administrator hat auf die Advanced Gateway Funktionen aller Tenants sofort vollen Zugriff!

Giuliano Bertello hat diese Situation und die Lösung über die API sehr gut in seinem Artikel Enable NSX Advanced Gateway Services on vCD 8.20 for Tenants with RBAC beschrieben.
Wer sich mit der API nicht so ganz anfreunden kann, kann sich auch das PowerShell Modul von Adrian Begg anschauen (ich bevorzuge das definitiv auch). Mit den Funktionen in dem PowerShell Modul lassen sich die neuen Rechte für die UI ganz komfortabel mit PowerShell freischalten.

Aktivieren der Advanced Gateway Services

Wie in dem Blog Artikel von Giuliano Bertello ausführlich beschrieben, stehen die Rechte dazu in der UI leider nicht out-of-the-box zur Verfügung, diese müssen erst freigeschaltet werden.

Mit Hilfe des PowerShell Modul von Adrian Begg habe ich zum Test das Recht „Organization vDC Gateway: Configure NAT“ freigeschaltet.

Add-CIOrgRight -OrgName TestOrg -Right "Organization vDC Gateway: Configure NAT"

Dieses steht nun auch in der UI zur Verfügung:

vCloud Director upgrade - Advanced Service Role NAT

Vorher hat die gesamte Kategorie „Gateway Advanced Services“ in der UI nicht existiert.

Nachdem das Recht aktiviert wurde und sich der User einmal ab- und angemeldet hat, kann er dann in meinem Beispiel auch NAT-Regeln erstellen und verändern:

vCloud Director upgrade - Advanced Service Gateway with NAT

Welche Rechte es alles gibt, kann mit dem importierten PowerShell Modul so angezeigt werden:

Get-CIOrgRights -OrgName TestOrg

Für unseren Zweck macht es sinn die Ausgabe auf die „Gateway Advanced Services“ zu beschränken:

Get-CIOrgRights -OrgName TestOrg | where {$_.Name -match "Organization vDC Gateway: Configure |Organization vDC Gateway: View " -and $_.name -notmatch "Services|Syslog|System"}

vCloud Director upgrade - PowerShell Advanced Service Roles

Um für alle VMware vCloud Director Organisationen die oben aufgelisteten Rechte freizuschalten kann dieses kleine Skript verwendet werden:

$Orgs = Get-Org
foreach ($Org in $Orgs) {
    $Rights = Get-CIOrgRights -OrgName $Org.name | where {$_.Name -match "Organization vDC Gateway: Configure |Organization vDC Gateway: View " -and $_.name -notmatch "Services|Syslog|System"}
    foreach ($Right in $Rights) {
        Add-CIOrgRight -OrgName $Org.name -Right $Right.Name
    }
}

VMware vCloud Director Upgrade – NSX Probleme

Ich muss direkt zu Beginn klar stellen, dass das sicher ein sehr spezifisches Problem ist. Es ist mir aber bei meinen Tests aufgefallen, daher erwähne ich es hier auch.

Versionen vor dem Upgrade:

  • vCenter 6.0 Update 2
  • ESXi 6.0 Update 2
  • vCloud Director 8.10.1
  • NSX 6.2.4
  • SQL Server 2012 SP1

Das Ziel ist im ersten Schritt:

  • vCloud Director 8.20
  • NSX 6.3.1

Somit kommt es gezwungener Maßen für eine gewisse Zeit zu dieser Situation:

  • vCloud Director 8.20
  • NSX 6.2.4

Und in genau dieser Situation tritt eine Besonderheit auf:

Wenn ein Edge Gateway in dieser Situation zu einem Advanced Gateway konvertiert wird und die Firewall vorher Deaktiviert war, ist sie auch weiterhin deaktiviert. Nur leider hat das anscheinend vorher bedeutet, aller Traffic wird zugelassen und nun wird er komplett blockiert. Mit NSX 6.3.1 ist nun nach dem Konvertieren die Firewall wieder angeschaltet und die Standard Regel ist Permit All.

Wenn jemand zu dieser Situation noch weitere Infos oder andere Blog Artikel hat, gerne Kommentieren. Ich konnte das aus Zeitgründen im Lab nicht weiter nach-verfolgen.

VMware vCloud Director Upgrade – neue URLs

Bisher haben die URLs für den Zugriff auf den vCloud Director so ausgesehen:

Tenant: https://<FQDN>/cloud/org/<OrgName>/*

Admin: https://<FQDN>/cloud/*

Mit der neuen Version 8.20 und der damit neu eingeführten HTML5 UI für Distributed Firewall und Gateway Advanced Services kommt eine neue oder eigentlich sogar zwei neue URLs hinzu:

Gateway Advanced Services: https://<FQDN>/tenant/network-edges/*

Distributed Firewall: https://<FQDN>/tenant/dfw/*

Diese URLs gelten für Tenant und Admin. Wer seinen Load Balancer bezüglich der URL´s etwas enger gezurrt hat, muss hier eventuell noch mal Hand anlegen nach dem vCloud Director Upgrade. Besonders weil die Distributed Firewall URL auch ohne das Recht „Manage Firewall“ zu öffnen ist.

VMware vCloud Director Upgrade – Mein Fazit

Fazit meiner ersten Tests des VMware vCloud Director Upgrade Prozesses ist leider ganz schön frustrierend, ohne einen ausführlichen Test im Vorfeld würde ich dieses Update auf keinen Fall empfehlen.

Um unerwünschte Effekte zu vermeiden  muss im Nachgang entweder das Recht für die Konvertierung der Edge Gateways („Convert to Advanced Gateway„) entzogen werden oder die Rechte der Kategorie Gateway Advanced Services für alle Orgs hinzugefügt werden. Genauso würde ich bezweifeln, dass allen Tenants direkt das Recht zur Freischaltung der Distributed Firewall gegeben werden wird.

vCloud Director upgrade - Convert to Advanced Service Gateway Role vCloud Director upgrade - Manage Firewall Role

 

Ich finde VMware könnte diese Situation etwas klarer in seinen Release Notes herausstellen. Dieses Known Issue könnte wohl entfernt darauf hinweisen:

Unexpected Rights Granted to Tenant Organizations After Upgrade 
When you upgrade to this release, a number of rights that are normally not granted to tenant organizations become available in those organizations and can be used in new roles that administrators of those organizations create.

Workaround: Use the vCloud API to edit the set of rights in the organization and remove the rights you do not want the organization to have.

Besser wäre es wohl gewesen im Upgrade Prozess alle Rechte mit dem Ist-Stand zu migrieren und der System Administrator (Provider) schaltet dann die zusätzlichen Rechte nach Bedarf frei.

Für die zusätzlichen URLs gilt ebenfalls, dass ich dazu einen Hinweiß in den Release Notes erwartet hätte. Es ist nicht ungewöhlich dass die die URLs aus Sicherheitsgründen explizit behandelt werden, z.B. https://<FQDN>/cloud/org/* von überall, aber https://<FQDN>/cloud/* nur aus bestimmten Netzen. Nun kommt zusätzlich mindestens https://<FQDN>/tenant/* von überall dazu.

Trotz dieser Probleme und Stolpersteine ist die Version 8.20 ein Release mit genialen neuen Features. Die Verwaltung der Distributed Firewall durch die Tenants ist ein lang erwartetes Feature und wurde sehr gut in der HTML5 UI umgesetzt. Zwei Wermutstropfen gibt es aber leider auch hier… Einfach mal den Abschnitt Distributed Firewall under the Hood im Artikel vCloud Director 8.20: Distributed Firewall lesen und selbst eine Meinung bilden.

Nicht so ganz geschickt finde ich auch, dass in der HTML5 UI  für Distributed Firewall und Gateway Advanced Services die Option für das Log von Firewall Aktionen fehlt. Diese muss der Provider nachträglich in der NSX Verwaltung nachpflegen wenn gewünscht. Dazu folgt aber sehr bald ein ausführlicher Artikel.

#LongLiveVCD

The post VMware vCloud Director Upgrade 8.10 to 8.20 appeared first on my cloud-(r)evolution.

Flattr this!

vCloud Director Edge Gateway Syslog Events

$
0
0

Es ist leider eine besondere Herausforderung für Service Provider die vCloud Director Edge Gateway Syslog Events der Tenants einzusammeln. Diese Logs sind zum Beispiel für eine Diagnose der Edge Gateway Firewall Aktionen notwendig. VMware beschreibt eine mögliche Lösung, wenn auch sehr oberflächlich, in dem vCAT-SP Guide Architecting a VMware vCloud Director® Solution for VMware vCloud Air™ Network unter dem Begriff Service Network. Ein anderer Ansatz den ich aber direkt verworfen habe ist, dass der Tenant innerhalb seines VMware vCloud Director VDC selbst eine VMware vRealize Log Insight Appliance bereitstellt und die Firewall und NAT Regeln für die Weiterleitung selbst erstellt.

Der Grundgedanke des Service Network ist, den Tenants, wenn ein Edge Gateway vorhanden ist, ein zusätzliches Netzwerk als External Network anzubinden. In diesem Netzwerk können dann Services wie Syslog oder andere Management Systeme untergebracht werden. Für einige Services genügt es, in diesem Netzwerk eine einzelne Instanz ohne weitere Anbindung zu haben. Für andere wiederum ist die Anbindung an globale Management Systeme notwendig. Syslog soll in meinem Fall unbedingt an ein übergeordnetes vRealize Log Insight Cluster angebunden werden, erfordert daher weitreichendere Konfigurationen als in dem vCAT-SP Guide beschrieben.

vCloud Director Edge Gateway Syslog Events – Konzept

Um die VMware vCloud Director Edge Gateway Syslog Events der Kunden sicher in das übergeordnete VMware vRealize Log Insight Cluster zu transportieren habe ich mir das folgende Konzept in meinem Lab erarbeitet.

  • Syslog Events werden an einzelne vRealize Log Insight Appliance im Service Network gesendet
  • einzelne vRealize Log Insight Appliance leitet an übergeordneten Cluster im Management Netzwerk weiter

Die einzelne vRealize Log Insight Appliance sitzt dabei auf einem NSX Logical Switch, kann also mit Distributed Firewall (DFW) geschützt werden und die Daten von einem Distributed Logical Router (DLR) in das globale Management Netz (klassisches VLAN) weitergeleitet werden.

vCloud Director Edge Gateway Syslog Events - Konzept

vCloud Director Edge Gateway Syslog Events – Umsetzung

NSX Logical Switch

Als „DMZ“ für die weiterleitende VMware vRealize Log Insight Appliance habe ich einen eigenen Logical Switch angelegt. Dieses Netz steht zu diesem Zeitpunkt erst einmal nicht im VMware vCloud Director zur Verfügung.

vCloud Director Edge Gateway Syslog Events - Logical Switch

NSX Distributed Logical Router

Um die vCloud Director Edge Gateway Syslog Events an das  übergeordnete VMware vRealize Log Insight Cluster weiterzuleiten, welches sich in einem klassischen VLAN (Name: VLAN1095) befindet habe ich einen DLR zum Routing zwischen diesen beiden Netzen angelegt.

vCloud Director Edge Gateway Syslog Events - DLR

vCloud Director Edge Gateway Syslog Events - DLR Interfaces

Das Routing Logging sollte genauso wie die Edge Gateway Syslog Einstellungen konfiguriert werden:

Die Routen aus dem übergeordneten Management Netz zu dem Netz 10.10.100.0/24 müssen in meinem Lab leider als Statische Routen auf den Relevanten Systemen (vRealize Log Insight Appliances, DNS Server, NTP Server) gesetzt werden.

NSX Distributed Firewall

Um die weiterleitende VMware vRealize Log Insight Appliance (Name: VLI10) best möglich zu schützen habe ich mit der Distributed Firewall nur die notwendigsten Services freigegeben.

  • Das Netz 192.168.95.0/24 ist in meinem Lab das übergeordnete Management Netz
  • Das Netz 10.10.100.0/24 ist in meinem Lab das Service Network

vCloud Director Edge Gateway Syslog Events - DFW

vCloud Director Default Syslog Servers

Damit neue Edge Gateways direkt den Syslog Server gesetzt bekommen kann im vCloud Director ein Default Syslog Server konfiguriert werden.

vCloud Director Edge Gateway Syslog Events - Default Syslog

Bereits bestehende Edge Gateways müssen einmal von Hand Synchronisiert werden.

vCloud Director Edge Gateway Syslog Events - Syncronize Edge

Die Synchronisation kann auch per VMware PowerCLI für alle Edge Gateway im vCloud Director Bestand gestartet werden:

Search-Cloud -QueryType EdgeGateway -Name * | Get-CIView | %{$_.SyncSyslogServerSettings()}

vCloud Director External Network

Um das zusätzliche External Network für die Edge Gateways im vCloud Director  zur Verfügung zu haben, muss das Netz mit dem passenden Subnet angelegt werden.

vCloud Director Edge Gateway Syslog Events - External Network

Dann kann den Tenant Edge Gateways der zusätzliche Uplink hinzugefügt werden. Das Default Gateway bleibt das „echte“ externe Netz.

vCloud Director Edge Gateway Syslog Events - Edge Uplink

vRealize Log Insight Forwarding

Die weiterleitende VMware vRealize Log Insight Appliance benötigt in meinem Setup keine weitere Konfiguration außer NTP und DNS. Nur die Weiterleitung muss natürlich eingerichtet werden.

vCloud Director Edge Gateway Syslog Events - Event Forwarding

Kleines Manko an meinem Lab Setup ist das fehlende SSL für die Weiterleitung. Ab VMware vRealize Log Insight 4.5 kann Weiterleitung per SSL das nur mit einem sauberen Zertifikat aktiviert werden.

vCloud Director Edge Gateway Syslog Events in Log Insight

Damit Log Einträge für bestimmte Firewall Aktionen überhaupt generiert werden, muss an der Firewall Regel unter Action noch die Zusatzoption „Log“ gesetzt werden – Standard ist „Do not log“.

Um mir schnell einen Überblick über die aktuellen Log Einstellungen der einzelnen Edge Firewall Regeln zu machen ist das PowerShell Modul PowerNSX absolut genial.

Alle vorhanden Edge Firewall Regeln anzeigen (ohne System Regeln):

Get-NsxEdge | Get-NsxEdgeFirewall | Get-NsxEdgeFirewallRule | where { $_.ruleType -notmatch 'internal' } | ft

vCloud Director Edge Gateway Syslog Events - PowerNSX - Get Edge Firewall Rules

Um für alle Edge Firewall User-Regeln das Logging zu aktivieren, habe ich mir dieses kleine PowerShell Skript erstellt:

foreach ( $Rule in (Get-NsxEdge | Get-NsxEdgeFirewall | Get-NsxEdgeFirewallRule | where { $_.ruleType -match 'user' })) {
    $URI = "/api/4.0/edges/$($Rule.EdgeID)/firewall/config/rules/$($Rule.ID)"
    $req = Invoke-NsxWebRequest -URI $URI -method get
    $Content = [xml]$req.Content
    $Content.firewallRule.loggingEnabled = "true"
    $response = Invoke-NsxWebRequest -URI $URI -method put -body $Content.firewallRule.OuterXml
}

Ein Update der Edge Firewall Rule per API in Postman könnte übrigens so aussehen:

vCloud Director Edge Gateway Syslog Events - PowerNSX - NSX API - Update Edge Firewall Rule

Leider kann im VMware vCloud Director 8.20 der Tanant die Option zum Loggen nicht immer selbst aktivieren, in der HTML5 UI fehlt diese Option bei den Firewall Aktionen. Also muss der Service Provider für alle Edge Gateways mit aktivierten Advanced Services diese Option selbst bei Bedarf setzen.

Ist das Log für eine Firewall Regel aktiviert (hier im Beispiel Drop) ist das Event auch in vRealize Log Insight zu finden.

Wer das NSX Content Pack kennt, dem ist eventuell aufgefallen, dass der benutzte Filter ein selbst erstelltes Field ist. Der originale funktioniert leider nicht.

Mein Field:

Content Pack Field:

Wer das ebenfalls gerne behoben hätte, darf gerne für meinen Log Insight Community Request Voten.

vCloud Director Distrubuted Firewall Syslog Events in Log Insight

Für diese Events ist keine besondere Konfiguration der Umgebung erforderlich, diese Daten werden direkt aus den ESXi Logs ausgelesen.

Das Problem mit der fehlende Option für das Log in der HTML5 UI ist aber ebenfalls vorhanden. Der Provider muss auch hier selbst eingreifen für die DFW Log´s.

Um mir schnell einen Überblick über die aktuellen Log Einstellungen der einzelnen DFW Regeln zu verschaffen ist das PowerShell Modul PowerNSX wieder absolut genial.

Alle vorhanden DFW Regeln mit PowerNSX anzeigen:

Get-NsxFirewallSection | %{Get-NsxFirewallRule -Section $_} | ft

vCloud Director Edge Gateway Syslog Events - PowerNSX - Get DFW Rules

Um bei allen DFW Regel bis auf die „Default Section“ das Logging zu aktivieren, hat Nick Bradford ein PowerNSX Beispiel Skript in dem GitHub Repository zur Verfügung gestellt:

foreach ( $section in (Get-NsxFirewallSection | ? { $_.name -notmatch 'Default Section Layer3' })) {
    $req = Invoke-NsxWebRequest -URI "/api/4.0/firewall/globalroot-0/config/layer3sections/$($section.id)" -method get
    $content = [xml]$req.Content
    foreach ($rule in $content.section.rule) { $rule.logged = "true" }
    $AdditionalHeaders = @{"If-Match"=$req.Headers.ETag}
    $response = Invoke-NsxWebRequest -URI "/api/4.0/firewall/globalroot-0/config/layer3sections/$($section.id)" -method put -extraheader $AdditionalHeaders -body $content.section.outerxml
    if ( -not $response.StatusCode -eq 200 ) {
        throw "Failed putting section $($section.name) ($($section.id)).  $($response.StatusCode) : $($response.StatusDescription)"
    }
    else {
        write-host "Enabled logging on all rules in Section $($section.name) ($($section.id))"
    }
}

Weiterführende Links

 

The post vCloud Director Edge Gateway Syslog Events appeared first on my cloud-(r)evolution.

Flattr this!

Veeam vSphere Interactions with PowerShell

$
0
0

Ich habe mir schon länger vorgenommen zwei meiner am häufig genutzten Produkte per PowerShell etwas näher zusammen zu bringen. Es geht darum, Veeam Backup & Replication und VMware vSphere etwas übergreifender per PowerShell zu verwalten oder zu überwachen. Dazu habe ich mein GitHub Projekt Veeam vSphere Interactions gestartet.

Wenn zwei unabhängige Produkte in einer Shell interagieren können, zeigt mit das wieder einmal wie mächtig PowerShell wirklich ist.

Um das aktuelle Version zu verwenden, bitte einfach den GitHub Export herunterladen, ZIP File extrahieren und Modul importieren.

Zum Beispiel per PowerShell:

# Download
wget https://github.com/mycloudrevolution/Veeam-vSphere-Interactions/archive/master.zip -OutFile C:\temp\master.zip

# Unzip
Add-Type -AssemblyName System.IO.Compression.FileSystem
function Unzip {
    param([string]$zipfile, [string]$outpath)
    [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
}

Unzip C:\temp\master.zip C:\temp\

# Import
Import-Module C:\temp\Veeam-vSphere-Interactions-master\Veeam-vSphere-Interactions.psd1

Nach dem erfolgreichen Import stehen nun die neuen Funktionen in der aktuellen PowerShell Session zur Verfügung.

Veeam vSphere Interactions - Get-Command

Veeam vSphere Interactions – Ziel

Das PowerShell Modul soll an VMware PowerCLI Nutzer gerichtet sein. Mit diesem Grundsatz werden die Funktionen als Input meist VMware vSphere Objekte (z.B. Virtuelle Maschinen) haben und diese werden dann über das Veeam PowerShell SnapIn mit der Veeam Backup & Replication Infrastruktur interagieren.

Veeam vSphere Interactions – Vorbereitung

Damit die Interaktion zwischen den beiden Produkten (VMware PowerCLI und Veeam PowerShell Snapin) funktioniert, muss darauf geachtet werden, dass das VMware vCenter im Veeam Backup & Replication Server korrekt erkannt werden kann.

Dafür muss für die PowerCLI Verbindung der gleiche Name, FQDN oder IP verwendet werden, wie das vCenter auch in Veeam Backup & Replication eingebunden wurde.

Hier ein Beispiel:

Das vCenter wurde mit folgendem Befehl verbunden:

Connect-VIServer -Server 192.168.3.101

Und auch in der Veeam Backup & Replication Konfiguration wurde für das VMware vCenter die IP 192.168.3.101 verwendet.

Veeam vSphere Interactions - vCenter Connection

Neben dem VMware vCenter muss in der gleichen PowerShell Session zusätzlich ein Veeam Backup & Replication Server verbunden werden:

Connect-VBRServer -Server 192.168.3.100

Veeam vSphere Interactions – Funktionen

Funktionen im Überblick:

Get-VeeamProtection Prüfung des Sicherungszustandes von VMs
Add-VeeamJobObject VMs zu Backup Job hinzufügen
Remove-VeeamJobObject VMs aus Backup Job entfernen
Start-VeeamRestore VMs schnell wiederherstellen
Start-VeeamQuickBackup
VMs schnell sichern

Get-VeeamProtection

Veeam vSphere Interactions - Get-VeeamProtection

Die Funktion hat als Input VMware vSphere VMs und prüft deren Protection State im Veeam Backup & Replication Server.

Was meint Protection State?

  • Gibt es Restore Points
  • Wie viele Restore Points sind vorhanden
  • Zeitpunkt des letzten Restore Points
  • Zeitpunkt des ersten Restore Points

Das sind die grundlegenden Infos die ich persönlich als essentiell ansehe. Für alles weitere werden dann ohnehin die Veeam eigenen Management Instrumente verwendet werden.

Hier geht es zum PowerShell Code: Get-VeeamProtection

Add-VeeamJobObject

Veeam vSphere Interactions - Add-VeeamJobObject

Diese Funktion hat neben den VMware vSphere VMs noch den Backup Job Namen als Input. Die gewünschten Objekte, in diesem Fall VMs, werden dem Backup Job hinzugefügt.

Sollte die VM bereits in dem Job vorhanden sein, bleibt die Erfolgsmeldung aus und die Übersicht der konfigurierten Objekte wird ausgegeben.

Hier geht es zum PowerShell Code: Add-VeeamJobObject

Remove-VeeamJobObject

Veeam vSphere Interactions - Remove-VeeamJobObject

Analog zur vorherigen Funktion können mit VMware vSphere VMs und dem Backup Job Namen als Input Objekte aus dem Backup Job entfernt werden.

Ist die VM nicht als Backup Objekt vorhanden wird eine Meldung ausgegeben.

Hier geht es zum PowerShell Code: Remove-VeeamJobObject

Start-VeeamRestore

Veeam vSphere Interactions - Start-VeeamRestore

Mit Hilfe dieser Funktion werden die VMware vSphere VMs aus dem Input zu dem letzten bekannten Restore Point wiederhergestellt.

Ist kein Restore Point bekannt wird ein Fehler ausgegeben.

Hier geht es zum PowerShell Code: Start-VeeamRestore

Start-VeeamQuickBackup

Veeam vSphere Interactions - Start-VeeamQuickBackup

Für alle VMware vSphere VMs aus dem Input wird ein Veeam Quick Backup durchgeführt.

Die Voraussetzungen für ein Quick Backup sind, mindestens ein Full Backup und die Zugehörigkeit zu einem Backup Job.

Hier geht es zum PowerShell Code: Start-VeeamQuickBackup

Veeam vSphere Interactions – Work in Progress

Das Veeam vSphere Interactions PowerShell Modul ist in vollem Umfang auch als GitHub Repository bereitgestellt. Zum jetzigen Zeitpunkt ist das Projekt für mich noch im Status „Work in Progress“.
Wenn sich jemand an weiteren Funktionen oder an Verbesserungen der bestehenden Funktionen beteiligen möchte, jederzeit gerne. Ich freue mich auch eure Pull Requests, Issues oder ganz einfach Kommentare hier zu dem Beitrag.

Veeam vSphere Interactions – Danke

Vielen Dank an Luca Dell’Oca für seinen Artikel, Automatically create Veeam backups using vCenter Moref IDs. Dieser zeigt sehr schön wie man VMware vSphere VMs eindeutig in Veeam Backup & Replication identifizieren kann.

The post Veeam vSphere Interactions with PowerShell appeared first on my cloud-(r)evolution.

Flattr this!

vCloud Director Federation Certificate Renewal Workflow

$
0
0

Als Service Provider ist die Automation aller operativen Tasks sehr wichtig um die Effizient und Skalierbarkeit hoch zu halten sowie Fehlerquellen und damit Kosten im Gegenzug gering zu halten. Einer dieser Tasks ist der vCloud Director Federation Certificate Renewal der in vielen Umgebungen ohne weitere Abhängigkeiten ausgeführt werden kann.

Der Beiname „Workflow“ im Titel dieses Beitrags weist schon darauf hin, dass es sich diesmal nicht um ein VMware PowerCLI Skript handelt, obwohl das natürlich auch möglich ist für die Erneuerung der Zertifikate.

$Orgs = Get-Org | Get-CIView
foreach ($Org in $Orgs) {
    if ($Org.Settings.OrgFederationSettings.Enabled -match "False") {
        $Org.Settings.OrgFederationSettings.RegenerateFederationCertificate()
    }
}

Ich habe mich für diesen Artikel und auch allgemein wieder etwas mehr dem VMware vRealize Orchestrator zugewandt, warum erläutere ich im nächsten Abschnitt. 

Warum VMware vRealize Orchestrator

Bevor ich in das eigentliche Thema einsteige, möchte ich kurz meine Beweggründe aufzeigt, warum ich für bestimmte Tasks den VMware vRealize Orchestrator einem reinen PowerShell Skript vorziehe.

Das fundamentale Problem mit der Automation kritischer, regelmäßigen Tasks abgebildet mit PowerShell Skripten ist die Skalierbarkeit und Zuverlässigkeit.

Nehmen wir mal diesen Task als Beispiel um das Problem aufzuzeigen:

Um das vCloud Director Federation Certificate Renewal aller Organisationen durchzuführen ist kein großes PowerShell Skript notwendig (wenn man es genau nimmt ist sogar weniger Code erforderlich als mit dem vRealize Orchestrator). Der eigentliche Aufwand liegt darin diesen wiederkehrenden Task zuverlässig einzuplanen und die Läufe lückenlos zu überwachen. Habe ich viele weitere Tasks, die ich zusätzlich auf dem gleichen System ausführen möchte kommen wir zu dem Problem der Skalierbarkeit. Das ausführende System wird früher oder später unter Lastproblemen leiden und damit auch die Zuverlässigkeit der Skripte sinken. Zum Thema Zuverläsigkeit möchte ich noch die nachträgliche analyse fehlgeschlagener Ausführungen hinzufügen, diese gestaltet sich meist auch schwierig mit PowerShell Skripten. 

Eine Workflow Engine wie der vRealize Orchestrator hat alle Werkzeuge um diese Probleme zu vermeiden bereits an Bord, sogar Clustering wäre möglich wenn vSphere HA nicht genügt. Mit der zusätzlichen Anbindung eines vRealize Log Insight Clusters sind in Bezug auf die Überwachung der Workflows keine Wünsche mehr offen. Das gleiche mit PowerShell zu erreichen ist nicht unmöglich aber wesentlich aufwändiger.

vCloud Director Federation Certificate Renewal

Wenn eine Organisation nur lokale User oder Standard LDAP User, hat das Federation Zertifikat für die Organisation keinerlei Relevanz. Problematisch wird es wenn ein SAML identity provider genutzt wird.

Beispiel für ungenutztes Zertifikat:

vCloud Director Federation Certificate Renewal Workflow - Web UI

Leider benachrichtigt der VMware vCloud Director jedoch trotzdem die Organisation Administrators bei drohendem Ablauf (Zertifikat ist ein Jahr gültig).

Federation Certificate Renewal Workflow

vCloud Director Federation Certificate Renewal Workflow

Um das Renewal nun voll automatisch und zyklisch ablaufen zu lassen, müssen für den Workflow alle vCloud Director Organisationen gefiltert werden, die Federation nutzen. Dabei wird eigentlich automatisch die „System Org“ auch mit herausgefiltert, zur Sicherheit habe ich das aber noch einmal explizit erzwungen.

//Get all Orgs
var orgs = host.getOrganizations();

//Exclude Federation Org
for(var i = orgs.length - 1; i >= 0; i--) {
	System.debug("Org name: " + orgs[i].name);
	System.debug("Org name: " + orgs[i].toAdminObject().settings.orgFederationSettings.enabled);
	if(orgs[i].toAdminObject().settings.orgFederationSettings.enabled || orgs[i].name === "System" ) {
		System.debug("Org name '" + orgs[i].name + "' removed from processing (Federation Enabled or System).");
       	orgs.splice(i, 1);
    }
}

System.log(orgs.length + " Orgs Found");

Wer den Filter in dem PowerCLI und dem JavaScript Snippet vergleicht, wird sehen, dass bei beiden am Ende auf die gleiche API zugegriffen wird.

 

PowerCLI:

$Org.Settings.OrgFederationSettings.Enabled -match "False"

JavaScript:

orgs[i].toAdminObject().settings.orgFederationSettings.enabled

Nach dem Filtern kann auf alle Organisationen der Standard Workflow „Regenerate Federation Certificate“ angewendet werden. Dazu wird über eine Schleife Anhand des Counters auf einen Wert nach dem Anderen im Array zugegriffen:

//Pick Org from Orgs
var org = orgs[ counter ];
System.log(org.name + " Org picked");

//Get AdminOrg from Org
vCloudAdminOrganisation = System.getModule("com.vmware.library.vCloud.Admin.Organization").getAdminOrganizationFromOrganization(org);

Input ist nur der vCloud Director Host:

vCloud Director Federation Certificate Renewal Workflow - Run

Federation Certificate Renewal Workflow Monoitoring

Mit dem VMware vRealize Log Insight Content Pack für die vRealize Orchestrator (7.0.1 +) ist es ohne weitere Anpassung möglich die Workflows und das System umfassend zu überwachend. Und damit sind wir auch wieder bei dem Einleitenden Thema, warum der vRealize Orchestrator für den Enterprise Einsatz einfacher zu nutzen ist als ein reines PowerShell Skript.

In-Workflow Log Events:

vCloud Director Federation Certificate Renewal Workflow - Log Insight Dashboard

vCloud Director Federation Certificate Renewal Workflow - Log Insight Log

Federation Certificate Renewal Workflow Download

Ich habe die aktuelle Version des Workflows als Sample zum Download bereitgestellt:

VMWARE {code}™ Sample Download

The post vCloud Director Federation Certificate Renewal Workflow appeared first on my cloud-(r)evolution.

Flattr this!

Using PowerShell to create a vCloud Director Tenant HTML Report

$
0
0

As we all know, VMware vCloud Director is a widely adopted IaaS platform for the service provider market. VMware vCloud Director offers a self-service web portal to manage your vApps, VMs, networks, and network functions (Edge Firewall, NAT, VPN, Load Balancer, DFWand Rrouting). But there is also a RESTful API, and a PowerShell Module offered for the administrators and tenants. With the help of the API, some third– party vendors offer an extended web portal (for example, OnApp). In this article, I’ll show you how to use the VMware vCloud Director PowerShell Module (part of the famous VMware PowerCLI) to extend the default UI with a vCloud Director Tenant HTML Report for your most important objects. Unfortunately, there is no reporting option offered by the self-service web portal itself.

The problem with extensive HTML reports created with PowerShell is that the ConvertTo-HTML Cmdlet is not really flexible. So I was looking for alternative ways and found the PowerShell module PowerStartHTML from Timothy Dewin. This module combines PowerShell with Bootstrap, a open source toolkit for developing with HTML, CSS, and JS. With this toolkit, I was able to create a report that contains the necessary information’s in a nicelooking format.

vCloud Director Tenant HTML Report

VMware PowerCLI for vCloud Director Basics

The latest version of VMware PowerCLI is available on PowerShell Gallery. So if you use PowerShell 5.0 or newer, you can install PowerCLI modules with one simple command:

Install-Module VMware.PowerCLI -Scope CurrentUser

After installation is successful, you can load all VMware modules using this command:

Get-Module -Name VMware* -ListAvailable | Import-Module

One of the loaded modules is VMware.VimAutomation.Cloud, which is for VMware vCloud Director. But be aware that not all commands work as a tenant. Some Ccmdlets are for administrative use only and others are for vCloud Air (which was sold to OVH).

All available vCloud Director Cmdlets (and one function) on version 6.5.1:

vCloud PowerCLI Cmdlets

The aliases for vCloud Air are removed from this screenshot. 

To connect to your VMware vCloud Director organization, the Cmdlet Connect-CIServer works as a provider administrator and also as a tenant. Tenants simplneed to add their organization during connection:

Connect-CIServer -Server <vCD FQDN> -Org <Org Name> [-Credential <PS Credential>]

Other PowerCLI vCloud Director examples:

Some interesting Cmdlets

Search-Cloud

The Search-Cloud Cmdlet is the fastest way to get vCloud Director objects via PowerCLI. You can also list some objects for that since no typical Get-* command is available (for example, Edge Gateways).

Example: List Edge Gateways:

Search-Cloud -QueryType EdgeGateway

All QueryTypes can be found in the VMware vSphere 6.5 Documentation Center.

Get-CIVApp

The Get-CIVApp Cmdlet lists all vCloud Director vApps. vApps are also known from VMware vSphere but are way more important in vCloud Director. A vApp can contain objects like VMs, networks, and network functions.

Example: List vApp ‚NetApp-HA‘:

Get-CIVApp -Name NetApp-HA

Get-CIVM

The Get-CIVM Cmdlet lists all vCloud Director VMs. VMs are in vCloud Director always children from vApps and also the Cmdlet can use Get-CIVApp as piped input.

Example: List all VMs from vApp ‚NetApp-HA‘:

Get-CIVApp -Name NetApp-HA | Get-CIVM

Bootstrap with PowerShell Basics

Firs I have to say I am no HTML pro and I would not have been able to create the report without the help of this great example from Timothy Dewin. Timothy created an awesome Veeam Backup & Replication HTML Report with his PowerStartHTML  PowerShell Module.

The function New-PowerStartHTML creates a new object with the necessary methods to create a full Bootstrap HTML page. The newly created object already includes the stylesheet for Bootstrap.

The two main methods to create your HTML page are:

$ps.Add(type,class,text)
$ps.Append(type,class,text)

Here’s an explanation from the README on GitHub:

The difference between Add is that it will remember the new element as the as the element. With Append, it remember the parent, so you can add an element at the same depth.

All the possible types and classes can be found in the Bootstrap documentation.

To get started with a simple HTML file, I created a report for all available modules on my PC. The main part of the report is a simple table.

$Modules = Get-Module -ListAvailable
$Path = "C:\Temp\Example.html"
$ps = New-PowerStartHTML -title "PowerStartHTML Example"
$ps.cssStyles['.bgtitle'] = "background-color:grey"
$ps.Main().Add("div","jumbotron").N()
$ps.Append("h1","display-3",("Module Report")).Append("p","lead","Module
Count: {0}" -f $Modules.Count).Append("p","font-italic","This Report lists all
Available PowerShell").N()
$ps.Main().Append("h2",$null,"Modules").N()
$ps.Add('table','table').Add("tr","bgtitle textwhite").Append("th",$null,"Module Name").Append("th",$null,"Module
Version").Append("th",$null,"Module Type").N()
foreach ($Module in $Modules) {
$ps.Add("tr").N()
$ps.Append("td",$null,$Module.Name).N()
$ps.Append("td",$null,$Module.Version).N()
$ps.Append("td",$null,$Module.ModuleType).N()
$ps.Up().N()
}$
ps.Up().N()
$ps.save($Path)
Start-Process $Path

simple Bootstrap example

This Eexample is not very complex and it maybe also be possible to create a simple table like this with the ConvertTo-HTML Cmdlet. But let’s get a little bit more complex and add the commands of each Module in a sub-section of the table.

$Modules = Get-Module -ListAvailable
$Path = "C:\Temp\Example.html"
$ps = New-PowerStartHTML -title "PowerStartHTML Example"
$ps.cssStyles['.bgsubsection'] = "background-color:#eee;"
$ps.cssStyles['.bgtitle'] = "background-color:grey"
$ps.Main().Add("div","jumbotron").N()
$ps.Append("h1","display-3",("Module Report")).Append("p","lead","Module
Count: {0}" -f $Modules.Count).Append("p","font-italic","This Report lists all
Available PowerShell").N()
$ps.Main().Append("h2",$null,"Modules").N()
$ps.Add('table','table').Add("tr","bgtitle textwhite").Append("th",$null,"Module Name").Append("th",$null,"Module
Version").Append("th",$null,"Module Type").N()
foreach ($Module in $Modules) {
$ps.Add("tr").N()
$ps.Append("td",$null,$Module.Name).N()
$ps.Append("td",$null,$Module.Version).N()
$ps.Append("td",$null,$Module.ModuleType).N()
$ps.Up().N()$ps.Add("td","bgsubsection").N()
$ps.Add("table","table bgcolorsub").N()
$ps.Add("tr").N()
$headers = @("Command Type","Name")
foreach ($h in $headers) {
$ps.Append("th",$null,$h).N()
}
$ps.Up().N()
[Array] $Commands = Get-Command -Module $Module.Name
foreach ($Command in $Commands) {
$ps.Add("tr").N()
$ps.Append("td",$null,$Command.CommandType).N()
$ps.Append("td",$null,$Command.Name).N()
$ps.Up().N()
}
$ps.Up().Up().N()
}
$ps.Up().N()
$ps.save($Path)
Start-Process $Path

Advanced Bootstrap Example

Okay, so that table is definitely more complex than what you can create with the ConvertTo-HTML Ccmdlet!

The vCloud Director Tenant HTML Report

Now that we’re familiar with the VMware PowerCLI vCloud Director Module and the basics of Bootstrap PowerShell handling, let`s get started with the report.

The first step is to decide which data is necessary for the vCloud Director Tenant HTML Report. This is my selection:

vCloud Director Tenant HTML Report - Design

With this set of data, we are now able to collect the object details from our VMware vCloud Director server using VMware PowerCLI.

Object details

Get Users

[Array] $Users = Get-CIUser

Get Catalogs

[Array] $Catalogs = Get-Catalog

Get Catalog Items

[Array] $Items = $Catalog.ExtensionData.CatalogItems.CatalogItem

Get VDCs

[Array] $OrgVdcs = Get-OrgVdc

Get VDC Edge Gateways

[Array] $Edges = Search-Cloud -QueryType EdgeGateway -Filter "Vdc==$($OrgVdc.Id)"

Get VDC Networks

[Array] $Networks = $OrgVdc | Get-OrgVdcNetwork

Get VDC vApps

[Array] $Vapps = $OrgVdc | Get-CIVApp

Get VDC vApp VMs

[Array] $VMs = $Vapp | Get-CIVM

Final vCloud Director Tenant HTML Report

I wanted to ship the vCloud Director Tenant HTML Report script as a PowerShell Module since that is the best way to also include the PowerStartHTML Module.

How to Create a Module

To create my PowerShell modules in a standardized way I use the Plaster Module with a customized template. For more details about Plaster and Plaster templates, you can read my blog article.

vCloud Director Tenant HTML Report - Plaster

The ‚VMware-vCD-TenantReport‘ Module

With my Plaster template and some manual modifications, I have created a Module with PowerStartHTML as a Sub-Module. The module also ships with a basic Pester test.

vCloud Director Tenant HTML Report - Module

The Report Script

The script to create the vCloud Director Tenant HTML Report is embedded in the exported Get-VcdTenantReport function, The usage is quite simple:

Get-VcdTenantReport -Server <vCD FQDN> -Org <Org Name> [-Credential $PSCred -Path C:\temp\report.html]

vCloud Director Tenant HTML Report - Get-VcdTenantReport

The report will be automatically opened in your default browser.

vCloud Director Tenant HTML Report PowerShell Code

function Get-VcdTenantReport {
<#
    .NOTES
    ===========================================================================
    Created by: Markus Kraus
    Twitter: @VMarkus_K
    Private Blog: mycloudrevolution.com
    ===========================================================================
    Changelog:
    1.0.0 - Inital Release
    1.0.1 - Removed "Test-IP" Module
    1.0.2 - More Detailed Console Log
    ===========================================================================
    External Code Sources:
    Examle Usage of BOOTSTRAP with PowerShell
    https://github.com/tdewin/randomsamples/tree/master/powershell-veeamallstat
    BOOTSTRAP with PowerShell
    https://github.com/tdewin/randomsamples/tree/master/powerstarthtml
    ===========================================================================
    Tested Against Environment:
    vCD Version: 8.20
    PowerCLI Version: PowerCLI 6.5.1
    PowerShell Version: 5.0
    OS Version: Windows 8.1
    Keyword: VMware, vCD, Report, HTML
    ===========================================================================

    .DESCRIPTION
    This Function creates a HTML Report for your vCloud Director Organization.

    This Function is fully tested as Organization Administrator.
    With lower permissions a unexpected behavior is possible.

    .Example
    Get-VcdTenantReport -Server $ServerFQDN -Org $OrgName -Credential $MyCedential

    .Example
    Get-VcdTenantReport -Server $ServerFQDN -Org $OrgName -Path "C:\Temp\Report.html"

    .PARAMETER Server
    The FQDN of your vCloud Director Endpoint.

    .PARAMETER Org
    The Organization Name.

    .PARAMETER Credential
    PowerShell Credentials to access the Eénvironment.

    .PARAMETER Path
    The Path of the exported HTML Report.

#>
#Requires -Version 5
#Requires -Modules VMware.VimAutomation.Cloud, @{ModuleName="VMware.VimAutomation.Cloud";ModuleVersion="6.5.1.0"}

[CmdletBinding()]
param(
    [Parameter(Mandatory=$True, ValueFromPipeline=$False)]
    [ValidateNotNullorEmpty()]
        [String] $Server,
    [Parameter(Mandatory=$True, ValueFromPipeline=$False)]
    [ValidateNotNullorEmpty()]
        [String] $Org,
    [Parameter(Mandatory=$False, ValueFromPipeline=$False)]
    [ValidateNotNullorEmpty()]
        [PSCredential] $Credential,
    [Parameter(Mandatory=$false, ValueFromPipeline=$False)]
    [ValidateNotNullorEmpty()]
        [String] $Path = ".\Report.html"

)

Process {

    # Start Connection to vCD

    if ($global:DefaultCIServers) {
        "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Disconnect existing vCD Server ..."
        $Trash = Disconnect-CIServer -Server * -Force:$true -Confirm:$false -ErrorAction SilentlyContinue
    }

    "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Connect vCD Server ..."
    if ($Credential) {
        $Trash = Connect-CIServer -Server $Server -Org $Org -Credential $Credential -ErrorAction Stop
    }
    else {
        $Trash = Connect-CIServer -Server $Server -Org $Org -ErrorAction Stop
    }
    "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Create HTML Report..."

    # Init HTML Report
    $ps = New-PowerStartHTML -title "vCD Tenant Report"

    #Set CSS Style
    $ps.cssStyles['.bgtitle'] = "background-color:grey"
    $ps.cssStyles['.bgsubsection'] = "background-color:#eee;"

    # Processing Data
    ## Get Main Objects
    [Array] $OrgVdcs = Get-OrgVdc
    [Array] $Catalogs = Get-Catalog
    [Array] $Users = Get-CIUser

    ## Add Header to Report
    $ps.Main().Add("div","jumbotron").N()
    $ps.Append("h1","display-3",("vCD Tenant Report" -f $OrgVdcs.Count)).Append("p","lead","Organization User Count: {0}" -f $Users.Count).Append("p","lead","Organization Catalog Count: {0}" -f $Catalogs.Count).Append("p","lead","Organization VDC Count: {0}" -f $OrgVdcs.Count).Append("hr","my-4").Append("p","font-italic","This Report lists the most important objects in your vCD Environmet. For more details contact your Service Provider").N()

    ## add Org Users to Report
    $ps.Main().Append("h2",$null,"Org Users").N()

    $ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"User Name").Append("th",$null,"Locked").Append("th",$null,"DeployedVMCount").Append("th",$null,"StoredVMCount").N()

    foreach ($User in $Users) {
        $ps.Add("tr").N()
        $ps.Append("td",$null,$User.Name).N()
        $ps.Append("td",$null,$User.Locked).N()
        $ps.Append("td",$null,$User.DeployedVMCount).N()
        $ps.Append("td",$null,$User.StoredVMCount).N()
        $ps.Up().N()

    }
    $ps.Up().N()

    ## add Org Catalogs to Report
    $ps.Main().Append("h2",$null,"Org Catalogs").N()

    foreach ($Catalog in $Catalogs) {
        $ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Catalog Name").N()
        $ps.Add("tr").N()
        $ps.Append("td",$null,$Catalog.Name).Up().N()

        $ps.Add("td","bgsubsection").N()
        $ps.Add("table","table bgcolorsub").N()
        $ps.Add("tr").N()

        $headers = @("Item")
        foreach ($h in $headers) {
            $ps.Append("th",$null,$h).N()
        }
        $ps.Up().N()

        ### add Itens of the Catalog to the Report
        [Array] $Items = $Catalog.ExtensionData.CatalogItems.CatalogItem

        foreach ($Item in $Items) {
            $ps.Add("tr").N()
            $ps.Append("td",$null,$Item.Name).N()

            $ps.Up().N()

        }

        $ps.Up().Up().N()
    }
    $ps.Up().N()

    ## add Org VDC`s to the Report
    $ps.Main().Append("h2",$null,"Org VDCs").N()

    foreach ($OrgVdc in $OrgVdcs) {
        $ps.Main().Add('table','table table-striped table-inverse').Add("tr").Append("th",$null,"VDC Name").Append("th",$null,"Enabled").Append("th",$null,"CpuUsedGHz").Append("th",$null,"MemoryUsedGB").Append("th",$null,"StorageUsedGB").Up().N()
        $ps.Add("tr").N()
        $ps.Append("td",$null,$OrgVdc.Name).Append("td",$null,$OrgVdc.Enabled).Append("td",$null,$OrgVdc.CpuUsedGHz).Append("td",$null,$OrgVdc.MemoryUsedGB).Append("td",$null,[Math]::Round($OrgVdc.StorageUsedGB,2)).Up().N()

        ### add Edge Gateways of this Org VDC to Report
        $ps.Main().Append("h3",$null,"Org VDC Edge Gateways").N()
        [Array] $Edges = Search-Cloud -QueryType EdgeGateway -Filter "Vdc==$($OrgVdc.Id)"

        foreach ($Edge in $Edges) {
            $ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Edge Name").N()
            $ps.Add("tr").N()
            $ps.Append("td",$null,$Edge.Name).Up().N()

            $ps.Add("td","bgsubsection").N()
            $ps.Add("table","table bgcolorsub").N()
            $ps.Append("tr").Append("td","font-weight-bold","HaStatus").Append("td",$null,($Edge.HaStatus)).N()
                $ps.Append("td","font-weight-bold","AdvancedNetworkingEnabled").Append("td",$null,$Edge.AdvancedNetworkingEnabled).N()
            $ps.Append("tr").Append("td","font-weight-bold","NumberOfExtNetworks").Append("td",$null,($Edge.NumberOfExtNetworks)).N()
                $ps.Append("td","font-weight-bold","NumberOfOrgNetworks").Append("td",$null,$Edge.NumberOfOrgNetworks).N()

            $ps.Up().Up().N()
        }
        $ps.Up().N()

        ### add Org Networks of this Org VDC to Report
        $ps.Main().Append("h3",$null,"Org VDC Networks").N()
        [Array] $Networks = $OrgVdc | Get-OrgVdcNetwork

        foreach ($Network in $Networks) {
            $ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"Network Name").N()
            $ps.Add("tr").N()
            $ps.Append("td",$null,$Network.Name).Up().N()

            $ps.Add("td","bgsubsection").N()
            $ps.Add("table","table bgcolorsub").N()
            $ps.Append("tr").Append("td","font-weight-bold","DefaultGateway").Append("td",$null,($Network.DefaultGateway)).N()
                $ps.Append("td","font-weight-bold","Netmask").Append("td",$null,$Network.Netmask).N()
            $ps.Append("tr").Append("td","font-weight-bold","NetworkType").Append("td",$null,($Network.NetworkType)).N()
                $ps.Append("td","font-weight-bold","StaticIPPool").Append("td",$null,$Network.StaticIPPool).N()

            $ps.Up().Up().N()
        }
        $ps.Up().N()

        ### add vApps of this Org VDC to Report
        $ps.Main().Append("h3",$null,"Org VDC vApps").N()

        [Array] $Vapps = $OrgVdc | Get-CIVApp

        foreach ($Vapp in $Vapps) {
            $ps.Add('table','table').Add("tr","bgtitle text-white").Append("th",$null,"vApp Name").Append("th",$null,"Owner").Up().N()
            $ps.Add("tr").N()
            $ps.Append("td",$null,$Vapp.Name).Append("td",$null,$Vapp.Owner).Up().N()

            #### add VMs of this vApp to Report
            $ps.Add("td","bgsubsection").N()
            $ps.Add("table","table bgcolorsub").N()
            $ps.Add("tr").N()

            $headers = @("Name","Status","GuestOSFullName","CpuCount","MemoryGB")
            foreach ($h in $headers) {
                $ps.Append("th",$null,$h).N()
            }
            $ps.Up().N()

            [Array] $VMs = $Vapp | Get-CIVM

            foreach ($VM in $VMs) {
                $ps.Add("tr").N()
                $ps.Append("td",$null,$VM.Name).N()
                $ps.Append("td",$null,$VM.Status).N()
                $ps.Append("td",$null,$VM.GuestOSFullName).N()
                $ps.Append("td",$null,$VM.CpuCount).N()
                $ps.Append("td",$null,$VM.MemoryGB).N()

                $ps.Up().N()

            }
            $ps.Up().Up().N()

        }
        $ps.Up().N()

    }
    $ps.save($Path)

    "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss") - Open HTML Report..."
    Start-Process $Path

}
}

The complete Module is also available as a GitHub repository.

Get the Module

I love automation, so I created a simple script to get the latest release of the vCloud Director Tenant HTML Report Module:

# Download
wget https://github.com/mycloudrevolution/VMware-vCD-TenantReport/archive/master.zip -OutFile C:\temp\master.zip

# Unzip
Add-Type -AssemblyName System.IO.Compression.FileSystem
function Unzip {
    param([string]$zipfile, [string]$outpath)
    [System.IO.Compression.ZipFile]::ExtractToDirectory($zipfile, $outpath)
}

Unzip C:\temp\master.zip C:\temp\

# Import
Import-Module "C:\temp\VMware-vCD-TenantReport-master\VMware-vCD-TenantReport.psd1"

 

The post Using PowerShell to create a vCloud Director Tenant HTML Report appeared first on my cloud-(r)evolution.

Flattr this!

PowerCLI – Automatic VM reconfigure

$
0
0

Vor einiger Zeit hat ein Kollege eine sehr spannende Idee an mich herangetragen (Vielen Dank Holger!). Es müsste doch möglich sein, zu erkennen wenn gewisse VMs herunterfahren werden um eine geplante Neukonfiguration durchzuführen - Quasi ein Automatic VM reconfigure. Das Herunterfahren könnte dann durch den Besitzer des Systems oder im Zuge von regelmäßigen Wartungen geschehen und die Anpassung der VM Parameter würden dann automatisch geschehen. Die typischen Parameter, welche offline zu verändern wären, sind RAM Größe und CPU Anzahl. Das Potential der Arbeitserleichterung war in meinen Augen enorm, daher habe ich mich umgehend an eine erste Version meins des VMware PowerCLI Skripts gesetzt. Es hat jedoch einige Anläufe gebraucht, bis ich damit zufrieden war.

Um dem User zusätzlich zu den Logs eine direkte Rückmeldung zu geben sieht die Ausgabe in der PowerShell Konsole so aus:

PowerCLI - Automatic VM reconfigure

Für die Erstellung eines Log File je Durchlauf habe ich die Write-Log PowerShell Logging Function von Mr. Automaton verwendet.

Der Aufruf des Skripts könnte beispielsweise so aussehen:

.\VmConfigTrigger.ps1 -VIServer myvCenter -Credential $MySavedCred -SleepTimer 60 -Test:$false

Automatic VM reconfigure im Detail

Für dieses Projekt gab es einige Punkte zu klären:

  • Wie kann in möglichst kurzen Intervallen erkannt werden ob die gewünschte VM ausgeschalten ist
  • Wie kann möglichst einfach festgelegt werden welche VM wie angepasst werden soll
  • Wie kann die Ausführung möglichst detailliert überwacht werden

Ich habe mich dazu entschieden alle ausgeschalteten VMs in dem angegebenen VMware vCenter aufzulisten und diese mit einem Konfigurationsfile zu vergleichen. Mit dem PowerCLI Cmdlet Get-View hat sich das als sehr effizient herausgestellt. Für das Konfigurationsfile habe ich mich für ein JSON File entschieden, das ist sehr schnell und fehlerunanfällig zu bearbeiten.

Das Konfigurationsfile

Die Konfiguration zum Automatic VM reconfigure soll den Namen der VM, die gewünschte RAM Größe in GB, die gewünschte Anzahl vCPUs und die Aktion nach dem Abschluss der Konfiguration beinhalten. Abgelegt wird das File einfach im Verzeichnis des PowerCLI Skripts.

[
    {
        "Name": "FirstVM",
        "RAM": "1",
        "CPU": "2",
        "Start": "no"


    },
    {
        "Name": "SecondVM",
        "RAM": "1",
        "CPU": "1",
        "Start": "no"
    }
]

Das PowerShell Skript

Im Kern handelt sich bei dem Automatic VM reconfigure Skript um eine Do-While Schleife deren Endbedingung ein Fehler ist. Somit läuft die Schleife solange, bis ein beliebiger Fehler auftritt. Um die Ausführung zu überwachen habe ich noch ein sehr ausführliches Logging mithilfe der Write-Log PowerShell Logging Function von Mr. Automaton hinzugefügt. Die Logs sollen in meinem Fall dann mit vRealize Log Insight eingesammelt und ausgewertet werden, dazu aber später mehr.

Skript Parameter:

Name Beschreibung
VIServer vCenter Name oder IP
[Credential] PowerShell Credential zur vCenter Verbindung
[SleepTimer] Zeit in Sekunden zwischen den Durchläufen
[Test] $True: Keine Änderung an der VM

#Requires -Version 4
 #Requires -Modules VMware.VimAutomation.Core, @{ModuleName="VMware.VimAutomation.Core";ModuleVersion="6.3.0.0"}
 [CmdletBinding()]
param(
    [Parameter(Mandatory=$true, ValueFromPipeline=$False)]
    [ValidateNotNullorEmpty()]
        [String] $VIServer,
    [Parameter(Mandatory=$false, ValueFromPipeline=$False, Position=0)]
    [ValidateNotNullorEmpty()]
            [pscredential] $Credential,
    [Parameter(Mandatory=$false, ValueFromPipeline=$False)]
    [ValidateNotNullorEmpty()]
        [int] $SleepTimer = 300,
    [Parameter(Mandatory=$false, ValueFromPipeline=$False)]
    [ValidateNotNullorEmpty()]
        [bool] $Test = $false
)

#region: Subfunction
<#
.Synopsis
   Write-Log writes a message to a specified log file with the current time stamp.
.DESCRIPTION
   The Write-Log function is designed to add logging capability to other scripts.
   In addition to writing output and/or verbose you can write to a log file for
   later debugging.
.NOTES
   Created by: Jason Wasser @wasserja
   Modified: 11/24/2015 09:30:19 AM

   Changelog:
    * Code simplification and clarification - thanks to @juneb_get_help
    * Added documentation.
    * Renamed LogPath parameter to Path to keep it standard - thanks to @JeffHicks
    * Revised the Force switch to work as it should - thanks to @JeffHicks

   To Do:
    * Add error handling if trying to create a log file in a inaccessible location.
    * Add ability to write $Message to $Verbose or $Error pipelines to eliminate
      duplicates.
.PARAMETER Message
   Message is the content that you wish to add to the log file.
.PARAMETER Path
   The path to the log file to which you would like to write. By default the function will
   create the path and file if it does not exist.
.PARAMETER Level
   Specify the criticality of the log information being written to the log (i.e. Error, Warning, Informational)
.PARAMETER NoClobber
   Use NoClobber if you do not wish to overwrite an existing file.
.EXAMPLE
   Write-Log -Message 'Log message'
   Writes the message to c:\Logs\PowerShellLog.log.
.EXAMPLE
   Write-Log -Message 'Restarting Server.' -Path c:\Logs\Scriptoutput.log
   Writes the content to the specified log file and creates the path and file specified.
.EXAMPLE
   Write-Log -Message 'Folder does not exist.' -Path c:\Logs\Script.log -Level Error
   Writes the message to the specified log file as an error message, and writes the message to the error pipeline.
.LINK
   https://gallery.technet.microsoft.com/scriptcenter/Write-Log-PowerShell-999c32d0
#>
function Write-Log
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true)]
        [ValidateNotNullOrEmpty()]
        [Alias("LogContent")]
        [string]$Message,

        [Parameter(Mandatory=$false)]
        [Alias('LogPath')]
        [string]$Path=$LogPath,

        [Parameter(Mandatory=$false)]
        [ValidateSet("Error","Warn","Info")]
        [string]$Level="Info",

        [Parameter(Mandatory=$false)]
        [switch]$NoClobber
    )

    Begin
    {
        # Set VerbosePreference to Continue so that verbose messages are displayed.
        $VerbosePreference = 'Continue'
    }
    Process
    {

        # If the file already exists and NoClobber was specified, do not write to the log.
        if ((Test-Path $Path) -AND $NoClobber) {
            Write-Error "Log file $Path already exists, and you specified NoClobber. Either delete the file or specify a different name."
            Return
            }

        # If attempting to write to a log file in a folder/path that doesn't exist create the file including the path.
        elseif (!(Test-Path $Path)) {
            Write-Verbose "Creating $Path."
            $NewLogFile = New-Item $Path -Force -ItemType File
            }

        else {
            # Nothing to see here yet.
            }

        # Format Date for our Log File
        $FormattedDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

        # Write message to error, warning, or verbose pipeline and specify $LevelText
        switch ($Level) {
            'Error' {
                Write-Error $Message
                $LevelText = 'ERROR:'
                }
            'Warn' {
                Write-Warning $Message
                $LevelText = 'WARNING:'
                }
            'Info' {
                Write-Verbose $Message
                $LevelText = 'INFO:'
                }
            }

        # Write log entry to $Path
        "$FormattedDate $LevelText $Message" | Out-File -FilePath $Path -Append -Encoding utf8
    }
    End
    {
    }
}
#endregion

#region: Main Loop
do{
    #region: Clear stuff
    $error.clear()
    #endregion

    #region: sleep and variables
    Start-Sleep -Seconds $SleepTimer
    Clear-Host
    $Date = $(get-date -format 'MMddyyyy-hhmmss')
    $LogPath = "$PSScriptRoot\Output-$Date.txt"
    $ErrorPath = "$PSScriptRoot\Error-$Date.txt"
    #endregion

    #region: Clean Log Files and start new log number
    Get-ChildItem $PSScriptRoot | Where-Object {$_.Name -match "Output-\d{8}\-\d{6}.txt"} | Sort-Object CreationTime -desc | Select-Object -Skip 10 | Remove-Item -Force
    Get-ChildItem $PSScriptRoot | Where-Object {$_.Name -match "Error-\d{8}\-\d{6}.txt"} | Sort-Object CreationTime -desc | Select-Object -Skip 10 | Remove-Item -Force
    Write-Log -Message "vmConfigTrigger log Number $date starts"
    #endregion

    #region: Start vCenter Connection
    Write-Log -Message "Starting to process vCenter connection to $VIServer ..."
    $OpenConnection = $global:DefaultVIServer | Where-Object { $_.Name -eq $VIServer }
    if($OpenConnection.IsConnected) {
        Write-Log -Message "vCenter is already connected..."
        $VIConnection = $OpenConnection
        }
        else {
            Write-Log -Message "Connecting vCenter..."
            if ($Credential) {
                $VIConnection = Connect-VIServer -Server $VIServer -Credential $Credential
            }
            else {
                $VIConnection = Connect-VIServer -Server $VIServer
            }
        }

    if (-not $VIConnection.IsConnected) {
        Write-Log -Message "vCenter connection failed" -Level Error
        }
    #endregion

    #region: Read Json Config
    ## Schema Example:
    ##[
    ##    {
    ##        "Name": "test",
    ##        "RAM": "2",
    ##        "CPU": "1"
    ##        "Start": "no"
    ##    },
    ##    {
    ##        "Name": "test2",
    ##        "RAM": "1",
    ##        "CPU": ""
    ##        "Start": "yes"
    ##    }
    ##]
    [Array] $Configs = Get-Content -Raw -Path "$PSScriptRoot\Config.json" | ConvertFrom-Json
    #endregion

    #region: Process Config
    ## Reads all VM names in the Config and compares them with poweredoff VMs in vCenter Inventory
    ## When VM is identified the given configuration is done
    if ($Configs) {
        Write-Log -Message "'$($Configs.count)' VMs were found in config file to process."

        foreach ($Config in $Configs) {
            $VmFilter = @{"Runtime.PowerState" ="poweredOff"; "Name" = $Config.name}
            [Array] $FilteredPoweredOffVms = Get-View -ViewType "VirtualMachine" -Property Name, Runtime, Config -Filter $VmFilter
            Write-Log -Message "'$($FilteredPoweredOffVms.count)' VMs found with matching name: '$($Config.name)'"
            if ($FilteredPoweredOffVms) {
                foreach ($FilteredPoweredOffVm in $FilteredPoweredOffVms) {
                    $VmChanged = $false
                    if ($FilteredPoweredOffVm.Name -eq $Config.Name) {
                        Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)' is unique identified!"

                        If ($($Config.RAM)) {
                            Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Requested RAM size: '$($Config.RAM)' GB."
                            Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Actual RAM size: '$(($FilteredPoweredOffVm.Config.Hardware.MemoryMB) / 1024)' GB."
                            Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': New RAM size: '$($Config.RAM)' GB."
                            if ($(($FilteredPoweredOffVm.Config.Hardware.MemoryMB) / 1024) -ne $($Config.RAM)) {
                                Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': RAM size needs to be changed."
                                if ($Test -eq $False) {
                                    $VmSpec = New-Object –Type VMware.Vim.VirtualMAchineConfigSpec –Property @{“MemoryMB” = $([single]($Config.RAM) * 1024)}
                                    $Trash = $FilteredPoweredOffVm.ReconfigVM($VmSpec)
                                    Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': RAM size is changed."
                                    $VmChanged = $true
                                    Remove-Variable -Name VmSpec
                                    if ($Trash) {
                                        Remove-Variable -Name Trash
                                    }
                                    }
                                    else {
                                        Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': RAM size is NOT changed, Test Mode requested."
                                        }

                                }
                                Else {
                                    Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': RAM size is already fine."
                                    }
                            }
                        If ($($Config.CPU)) {
                            Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Requested vCPU count: '$($Config.CPU)' vCPUs."
                            Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Actual vCPU Count: '$($FilteredPoweredOffVm.Config.Hardware.NumCpu)'."
                            Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': New vCPU count: '$($Config.CPU)'."
                            if ($($FilteredPoweredOffVm.Config.Hardware.NumCPU) -ne $($Config.CPU)) {
                                Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': vCPU count need to be changed."
                                if ($Test -eq $False) {
                                    $VmSpec = New-Object –Type VMware.Vim.VirtualMAchineConfigSpec –Property @{“NumCPUs” = $Config.CPU}
                                    $Trash = $FilteredPoweredOffVm.ReconfigVM($VmSpec)
                                    Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': vCPU count is changed."
                                    $VmChanged = $true
                                    Remove-Variable -Name VmSpec
                                    if ($Trash) {
                                        Remove-Variable -Name Trash
                                    }
                                    }
                                    else {
                                        Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': vCPU count is NOT changed, Test Mode requested."
                                        }
                                }
                                Else {
                                    Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': vCPU count is already fine."
                                    }
                            }
                        if ($VmChanged -eq $true) {
                            Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Config was changed."
                            If ($($Config.Start) -eq "yes") {
                                Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Needs to be powered on."
                                $Trash = $FilteredPoweredOffVm.PowerOnVM_Task($null)
                                if ($Trash) {
                                    Remove-Variable -Name Trash
                                }
                                }
                                elseIf ($($Config.Start) -eq "no") {
                                    Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Needs NOT to powered on."
                                    }
                                    else {
                                        Write-Log -Message "VM '$($FilteredPoweredOffVm.Name)': Invalid VM start configuration."
                                        }
                            }

                        }
                        Else {
                            Write-Log -Message "Name: '$($Config.Name)' was not unique identified in VM '$($FilteredPoweredOffVm.Name)'!" -Level Warn
                            }
                    }
                }
            }

        }
        else {
            Write-Log -Message "Failed to Read Config File!" -Level Warn
            }
    #endregion

    #region: Error Handling
    if ($error.Count -ne 0) {
        Write-Log -Message "A Global Error occured, Script will stop! Problem needs to be resolved and then the Script can be restarted. `n$($error) " -Level Error
        "Last Error: " +  $($error[0]) | Out-File -FilePath $ErrorPath -Append -Encoding utf8
        }
    #endregion

    #region: Finalize log number and cleanup
    Write-Log -Message "vmConfigTrigger log Number $date ends"
    Remove-Variable -Name Config, Configs, Date, FilteredPoweredOffVm, FilteredPoweredOffVms, VmChanged, VmFilter, LogPath, ErrorPath, OpenConnection, VIConnection
    [System.GC]::Collect()
    #endregion
}
while ($error.Count -eq 0)
#endregion

Die Handhabung

Das Skript kann zum Beispiel als geplanter Task mit einem täglichen Neustart eingeplant werden. Soll eine neue VM Konfiguration der Planung hinzugefügt werden, kann jederzeit das JSON File angepasst werden. Das Config File wird nach jedem Loop neu eingelesen.

Aber auch ein manueller Start, bis die gewünschte Änderung durchführt wurde ist natürlich denkbar.

Ressourcennutzung

Ich habe bei der Entwicklung des Automatic VM reconfigure Projekts versucht den Verbrauch den Ressourcen während der Ausführung so gering wie möglich zu halten. Also so wenig wie möglich Variablen, kein „Write-Host“ und auch die genutzten Variablen werden wenn möglich immer wieder gelehrt mit einer abschließenden Garbage Collection

[System.GC]::Collect()
 .

Mit diesen Maßnahmen könnte ich bei einer Umgebung  mit ca. 2000 VMs den verwendeten RAM auf 80 – 160 MB drücken. Wenn ihr andere Erfahrungen macht oder noch Tipps habt um das weiter zu optimieren freue ich mich über euren Kommentar!

Automatic VM reconfigure Log Aufbereitung

Ein wichtiger Bestandteil ist die lückenlose Log Auswertung um einerseits Fehler sofort zu erkennen und andererseits die vorgenommen Konfiguration zu kontrollieren. Dazu verwende ich den VMware vRealize Log Insight Agent um das Log des Skripts einzusammeln und auszuwerten.

Automatic VM reconfigure - vLI Dashboard

vRealize Log Insight Dashboard

Automatic VM reconfigure - vLI Full Log

vRealize Log Insight Log

Automatic VM reconfigure - vLI Error

vRealize Log Insight Error

Der Windows Agent verwendet durch das optimierte Log des PowerShell Skripts eine sehr simple Konfiguration:

Automatic VM reconfigure - vLI Agent Config

Das in der Konfiguration aufgeführte Error Log soll die Nachvollziehbarkeit des Automatic VM reconfigure Skripts noch weiter steigern. Dort werden nur die Errors hingeschrieben:

Automatic VM reconfigure - vLI Error Log File

 

Automatic VM reconfigure GitHub Projekt

Das Skript is wie üblich auch wieder als GitHub Projekt verfügbar:

VmConfigTrigger Project

 

The post PowerCLI – Automatic VM reconfigure appeared first on my cloud-(r)evolution.

Flattr this!


NSX Edge Gateway to vCloud Org Relationship

$
0
0

Für einige Administrative Tasks ist es leider notwendig die NSX Edge Gateways in einer VMware vCloud Director Umgebung den Orgs (Tenants) zuzuordnen. In meinem Fall waren es anstehende Edge Gateway Updates nach einem NSX Update. Die Zuordnung ist zwar sehr einfach aus VMware vCloud Director Sicht aber leider komplex aus VMware NSX Sicht, da sich die Namen der Objekte nicht decken müssen (z.B. verursacht durch nachträgliches Umbenennen).  Dazu kommen noch Edge Gateways die durch ein vApp Netzwerk erzeugt wurden, diese tauchen auch im VMware vCloud Director nicht zentral auf. Die Lösung um die NSX Edge Gateway to vCloud Org Relationship aufzulösen sollte mal wieder ein PowerShell Skript sein, und sogar ein ziemlich simples.

Das Problem

Die Ansicht aus dem VMware NSX vCenter Plugin lässt leider keinen offensichtlichen Verweis auf die VMware vCloud Director Organisation zu. Hilfreich könnte nur ein gutes Namensschema sein. Dieses ist aber spätestens bei vApp Netzwerken hinfällig, in dem Fall vergibt der Tenant mit dem vApp Netzwerknamen selbst den Edge Gateway Namen (in meinem Beispiel „Restore Test“).

NSX Edge Gateway to vCloud Org Relationship - NSX Edges

Die Lösung

Das vorherige Beispiel legt die Lösung bereits nahe, denn NSX realisiert die Mandantentrennung auch anhand von Tenants. Der Tenant Name im NSX ist die Id der vCloud Director Organistion.

Mit diesem Wissen und zwei PowerShell Modulen (PowerCLI und PowerNSX) lässt sich also eine Verbindung herstellen.

PowerNSX NSX Edge Gatway:

NSX Edge Gateway to vCloud Org Relationship - PowerNSX Edges

Man beachte das Feld „tenant“.

PowerCLI vCloud Director Org:

NSX Edge Gateway to vCloud Org Relationship - vCD Orgs

Die PowerCLI Id der Org beinhaltet die echte Tenant ID, welche dann identisch mit dem NSX Tenant is.

NSX Edge Gateway to vCloud Org Relationship Script

Um den kleinen Report zu erzeugen ist es neben dem Laden der beiden PowerShell Module (PowerCLI und PowerNSX) noch notwendig eine Verbindung zu dem betreffenden vCloud Director und dem NSX Manager herzustellen. Damit kann die Verbindung zwischen vCloud Org und NSX Edge Gatway hergestellt werden.

NSX Edge Gateway to vCloud Org Relationship

Import-Module VMware.VimAutomation.Cloud, PowerNSX
Connect-CIServer vcd.lab.local
Connect-NsxServer -vCenterServer vcs01.lab.local

$Orgs = Get-Org
$Edges = Get-NsxEdge

$myView = @()
Foreach ($Edge in $Edges) {
    $Report = [PSCustomObject] @{
            Name = $Edge.Name
            VcdOrg = ($orgs | where {$_.Id -match $edge.Tenant}) 
       }
    $MyView += $Report
}

$MyView | Sort UpdateAvailable, VcdOrg |  ft -AutoSize

Zeile 1: vCloud PowerCLI und PowerNSX Modul laden

Zeile 2: vCloud Director verbinden

Zeile 3: NSX Manager verbinden über das vCenter

Zeile 5-6: Objekte Sammeln

Zeile 8-17: Objekte in Relation bringen und Report erstellen

Zeile 12: Vergleich der beiden Id`s

The post NSX Edge Gateway to vCloud Org Relationship appeared first on my cloud-(r)evolution.

Flattr this!

Veeam Backup Validator PowerShell Pester Test

$
0
0

Diese Woche wurde mir wieder einmal ein sehr unterschätztes Tool für Veeam Backup & Replication ins Bewusstsein gerufen, der Veeam Backup Validator. Mit diesem Kommandozeilentool können die Veeam Backup Files überprüft werden. Die Syntax ist relativ simpel aber aufwendig wenn man eine große Anzahl von Backups überprüfen möchte. Um die Validierung großer Mengen an Backup Jobs und Backup Files so einfach wie möglich zu gestalten, habe ich mir einen Veeam Backup Validator PowerShell Pester Test geschrieben.

Veeam Backup Validator PowerShell Pester Test

Der von mir verfasste Pester Test besteht aus zwei Teilschritten:

  1. Backup Files der aktuell vorhandenen Jobs überprüfen
  2. Überprüfung der Veeam Backup Metadata Files unterhalb des Pfades des Pester Test Skript

Bitte bei der Ausführung beachten, dass durch den Veeam Backup Validator enorm Disk Read erzeugt werden kann:

Veeam Backup Validator Test load

Veeam Backup Validator für Backup Jobs

Dieser Test ist der aufwendigere der Beiden, denn hier muss zu aller erst eine Verbindung zum Veeam Backup & Replication Server hergestellt werden um die aktuellen Jobs auszulesen. Mit diesen Informationen kann dann der Veeam Backup Validator gestartet werden.

Beispiel:

veeam.backup.validator.exe /backup:"Backup Job 1"

Um jedoch den Veeam Backup Validator Pester Test zu realisieren werden die Ergebnisse in ein XML File geschrieben, welches dann wieder ausgewertet wird.

veeam.backup.validator.exe /silence /format:xml /report:"C:\temp.report.xml" /backup:"Backup Job 1"

XML Ausgabe:

<?xml version="1.0" encoding="utf-8"?>
<Report>
  <Info>Veeam Backup Validator Version 9.5.0.0
Copyright © Veeam Software AG. All rights reserved.</Info>
  <Info>Parameters:</Info>
  <Parameters>
    <Parameter Name="File:">D:\Backup\Backup Job 1\Backup Job 1.vbm</Parameter>
    <Parameter Name="Format:">Xml</Parameter>
    <Parameter Name="Report:">D:\Backup Job 1.vbm.xml</Parameter>
    <Parameter Name="Silence:">yes</Parameter>
    <Parameter Name="Skip:">no</Parameter>
  </Parameters>
  <VMProcessing>
    <Info>Reading file summary...</Info>
    <FileSummary>
      <Parameter Name="Storage path:">D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">summary.xml (8,9 KB)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">test2.vmx (2,7 KB)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">test2.nvram (8,5 KB)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">test2.vmdk (542,0 B)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">test2-flat.vmdk (16,0 GB)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">FsAwareMeta:eb386d08-554e-4369-bfc4-619c6ec17df6:2000 (100,0 B)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">summary.xml (8,6 KB)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">test.vmx (1,9 KB)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">test.vmdk (540,0 B)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">test-flat.vmdk (16,0 GB)</Parameter>
      <Parameter Name="D:\Backup\Backup Job 1\Backup Job 1D2017-08-25T215407.vbk, D:\Backup\Backup Job 1\Backup Job 1D2017-09-04T223507.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T215841.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T223707.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224001.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224655.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-09-05T224816.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T214632.vib, D:\Backup\Backup Job 1\Backup Job 1D2017-11-05T221631.vbk">FsAwareMeta:29cf5dc5-cba2-4d5b-8701-4c6b1bfb8cb5:2000 (100,0 B)</Parameter>
    </FileSummary>
    <Progress>
      <Info>Validating test2.vmx</Info>
      <FileName>test2.vmx</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating test2.nvram</Info>
      <FileName>test2.nvram</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating test2.vmdk</Info>
      <FileName>test2.vmdk</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating test2-flat.vmdk</Info>
      <FileName>test2-flat.vmdk</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating FsAwareMeta:eb386d08-554e-4369-bfc4-619c6ec17df6:2000</Info>
      <FileName>FsAwareMeta:eb386d08-554e-4369-bfc4-619c6ec17df6:2000</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating test.vmx</Info>
      <FileName>test.vmx</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating test.vmdk</Info>
      <FileName>test.vmdk</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating test-flat.vmdk</Info>
      <FileName>test-flat.vmdk</FileName>
      <Percentage>100</Percentage>
    </Progress>
    <Progress>
      <Info>Validating FsAwareMeta:29cf5dc5-cba2-4d5b-8701-4c6b1bfb8cb5:2000</Info>
      <FileName>FsAwareMeta:29cf5dc5-cba2-4d5b-8701-4c6b1bfb8cb5:2000</FileName>
      <Percentage>100</Percentage>
    </Progress>
  </VMProcessing>
  <Statistics>
    <Parameter Name="Backup files count:">9</Parameter>
    <Parameter Name="Incomplete backup files count:">0</Parameter>
    <Parameter Name="Failed backup files count:">0</Parameter>
    <Parameter Name="Files count:">9</Parameter>
    <Parameter Name="Total size:">32,0 GB</Parameter>
  </Statistics>
  <ResultInfo>
    <Result>Success</Result>
    <Info>Validation completed successfully.</Info>
  </ResultInfo>
  <DateInfo>Created by VEEAM-01\Administrator at 08.11.2017 22:45:52</DateInfo>
</Report>

Um alle Veeam Backup Jobs in einem PowerShell Skript zu validieren hat unter anderem Christopher Glémot bereits einen tollen Artikel veröffentlicht.

Veeam Backup Validator für Backup Files

Der zweite Test könnte ohne eine Verbindung zum Veeam Backup & Replication Server durchführt werden. Es werden nur die *.vbm Files (Veeam Backup Metadata File) in dem Pfad des Pester Test Skripts rekursiv aufgelistet und überprüft.

Beispiel:

veeam.backup.validator.exe /file:"G:\Backups\Management\Management.vbm"

Die XML Ausgabe würde wieder nach dem gleichen Schema funktionieren (HTML ginge natürlich auch, ist aber komplexer zu verarbeiten).

Veeam Backup Validator Pester Test Skript

Ein Aufruf einer externen Applikation ist in PowerShell für gewöhnlich kein Problem und es gibt verschiedenste Wege das zu tun. Die veeam.backup.validator.exe ist jedoch, wie sich herausgestellt hat sehr empfindlich. Daher in diesem Skript der aufwendige Aufruf über Start-Process. Auch in der PowerShell ISE bitte nicht wundern wenn Backups als fehlerhaft angezeigt werden (Hier ein Beitrag aus dem Veeam Forum: Problem running „Veeam.Backup.Validator.exe“ in PowerShell).

<#
    .EXAMPLE
    Invoke-Pester -Script @{ Path = "D:\VeeamBackupValidator.Tests.ps1"; Parameters = @{ BRHost="localhost"} }
#>

$BRHost = $Parameters.Get_Item("BRHost")

Describe "Veeam Backup Validator" {

    Add-PsSnapin -Name VeeamPSSnapIn
    $OpenConnection = (Get-VBRServerSession).Server
    if($OpenConnection -eq $BRHost) {
    } elseif ($OpenConnection -eq $null ) {
	    Connect-VBRServer -Server $BRHost
        } else {
            Disconnect-VBRServer
            Connect-VBRServer -Server $BRHost
            }

    $Jobs = Get-VBRBackup

    $testCase = $Jobs | Foreach-Object {@{Job = $_.name}}
    It "Backup File for Job '<Job>' should be valid " -TestCases $testCase {
        param($Job)

        [String] $Report = $PSScriptRoot + $Job + ".xml"
        $EXEPath = $env:ProgramFiles + "\Veeam\Backup and Replication\Backup\veeam.backup.validator.exe"
        Start-Process $EXEPath  " /silence /format:xml /report:`"$Report`" /backup:`"$Job`" " -Wait
        $Report | Should Exist
        $XMLContent = [XML] (Get-Content $report )
        (($XMLContent.Report.Statistics.Parameter | Where-Object {$_.Name -eq "Failed VM count:"})."#text") | Should Be 0
        Remove-Item $Report -Force
    }

    $Backups = Get-ChildItem $PSScriptRoot -Include *.vbm -Recurse
    $testCase = $Backups | Foreach-Object {@{file = $_}}
    It "Backup File  '<file>' should be valid" -TestCases $testCase {
        param($File)

        [String] $Report = $PSScriptRoot + $File.name + ".xml"
        $EXEPath = $env:ProgramFiles + "\Veeam\Backup and Replication\Backup\veeam.backup.validator.exe"
        Start-Process $EXEPath  " /silence /format:xml /report:`"$Report`" /file:`"$File`" " -Wait
        $Report | Should Exist
        $XMLContent = [XML] (Get-Content $Report )
        (($XMLContent.Report.Statistics.Parameter | Where-Object {$_.Name -eq "Failed backup files count:"})."#text") | Should Be 0
        Remove-Item $Report -Force
    }

}

 

The post Veeam Backup Validator PowerShell Pester Test appeared first on my cloud-(r)evolution.

Flattr this!

Veeam Plugin for PoshBot chat bot

$
0
0

Vor kurzem bin ich auf das Chat Bot Projekt PoshBot gestoßen, dabei handelt es sich um einen in PowerShell verfassten Slack Bot. Da ich diese Art des operativen Vorgehens schon länger spannend finde, habe ich mich daran gesetzt durch mein eigenes Veeam Plugin for PoshBot die Funktionalität etwas zu erweitern. Denn nur durch relevante Befehle und Funktionen wird ein solches Tool vom ‚Spielzeug‘ auch  zu einem echten Hilfsmittel.
Das PoshBot Projekt macht es einem durch seine gute Dokumentation wirklich sehr einfach einen Einstieg zu finden. Innerhalb von weniger Stunden war ich in der Lage die ChatBot App in meinen Slack Channel einzubinden und den ersten Befehl meines eigenen Plugins aufzurufen.

Veeam Plugin for PoshBot - Get-VeeamRepositories

Mittlerweile habe ich noch zwei weitere Kommandos hinzugefügt und es folgen hoffentlich bald noch viele weitere.

Veeam Plugin for PoshBot - Get-VeeamJobSessions

Veeam Plugin for PoshBot - Get-VeeamJobs

Update 30.11.2017:

Veeam Plugin for PoshBot - Start-VeeamQuickBackup

Wie Starte ich PoshBot

Ich habe meinen Einstieg in das Thema durch den tollen Artikel von Warren F. gefunden. In diesem Artikel werden unter anderem verschiedene Wege aufgeführt wie man den PoshBot Prozess startet (ist auch in der ReadTheDocs Doku des Projekts zu finden). Ich habe mir der Einfachheit halber eine PowerShell Funktion geschrieben um den Chat Bot in meiner Konfiguration nach Bedarf zu starten. In der Produktion ist sicher die Implementation als Dienst sinnvoller.

Allgemeine Voraussetzungen:

Veeam Plugin Voraussetzungen:

  • Veeam PowerShell Snapin
  • User hat Vollzugriff im Veeam Backup & Replication Server
    • Egal ob manuell gestartet oder als Dienst ausgeführt
  • Nicht zwingend erforderlich aber ratsam wäre es, PoshBot direkt auf dem Veeam Backup & Replication Server auszuführen
    • dadurch erspart man sich bei den Kommandos den optionalen Parameter  
      --brserver

function Start-VeeamPoshBot ($Token) {
    Import-Module -Name PoshBot
    $botParams = @{
        Name = 'veeambot'
        BotAdmins = @('vmarkus_k')
        CommandPrefix = '!'
        LogLevel = 'Verbose'
        BackendConfiguration = @{
            Name = 'SlackBackend'
            Token = $Token
        }
        AlternateCommandPrefixes = 'bender', 'hal'
    }

    $myBotConfig = New-PoshBotConfiguration @botParams

    Start-PoshBot -Configuration $myBotConfig

}

Input Parameter für die Funktion ist dann nur noch der Slack API Token für den Bot (vorausgesetzt das PoshBot Modul ist bereits Installiert).

Start-VeeamPoshBot -Token '<Your API Token>'

Mein Veeam Plugin for PoshBot

In dem Artikel von Warren F wird auch auf die Entwicklung von Plugin für PoshBot eingegangen. Ich fand jedoch den Abschnitt Developing Plugins der Projekt Dokumentation etwas übersichtlicher.

Was mich nun wirklich begeistert hat an dem PoshBot Konzept ist, dass man seine bestehenden PowerShell Funktionen mit wenigen Anpassungen zu einem PoshBot Plugin umwandeln kann. Genau das habe ich auch mit meinem PRTG Veeam Advanced Sensor gemacht indem ich dieses Skript in zwei PowerShell Funktionen aufgeteilt habe: Get-VeeamRepositoriesGet-VeeamJobSessions und Get-VeeamJobs. Sehr schnell war ich aber mit dem Detailgrad der Ausgabe von Get-VeeamJobSessions unzufrieden und habe mit Hilfe des PowerShell-VeeamAllStats Moduls von Timothy Dewin meine Funktion erweitert.

Get-VeeamRepositories

Die Zeilen 13-16 und 94-105 sind die einzigen PoshBot spezifischen Ergänzungen die aus einer normalen PowerShell Funktion ein PoshBot Kommando mit Aliasen, Rechten und übersichtlicher Ausgabe macht

function Get-VeeamRepositories {
        <#
        .SYNOPSIS
        Get Veeam Repositories
        .EXAMPLE
        !Get-VeeamRepositories
        .EXAMPLE
        !Repos
        .EXAMPLE
        !VeeamRepositories
        #>

        [PoshBot.BotCommand(
                Aliases = ('Repos', 'VeeamRepositories'),
                Permissions = 'read'
        )]
        [cmdletbinding()]
        param(
                [Parameter(Position=0, Mandatory=$false)]
                [string] $BRHost = "localhost"
        )

        #region: Functions
        Function Get-vPCRepoInfo {
                [CmdletBinding()]
                param (
                        [Parameter(Position=0, ValueFromPipeline=$true)]
                        [PSObject[]]$Repository
                )
                Begin {
                        $outputAry = @()
                        Function New-RepoObject {param($name, $repohost, $path, $free, $total)
                        $repoObj = New-Object -TypeName PSObject -Property @{
                                        Target = $name
                                        RepoHost = $repohost
                                        Storepath = $path
                                        StorageFree = [Math]::Round([Decimal]$free/1GB,2)
                                        StorageTotal = [Math]::Round([Decimal]$total/1GB,2)
                                        FreePercentage = [Math]::Round(($free/$total)*100)
                                }
                                Return $repoObj | Select-Object Target, RepoHost, Storepath, StorageFree, StorageTotal, FreePercentage
                        }
                }
                Process {
                        Foreach ($r in $Repository) {
                                # Refresh Repository Size Info
                                try {
                                        [Veeam.Backup.Core.CBackupRepositoryEx]::SyncSpaceInfoToDb($r, $true)
                                }
                                catch {
                                        Write-Debug "SyncSpaceInfoToDb Failed"
                                }

                                If ($r.HostId -eq "00000000-0000-0000-0000-000000000000") {
                                        $HostName = ""
                                }
                                Else {
                                        $HostName = $($r.GetHost()).Name.ToLower()
                                }
                                $outputObj = New-RepoObject $r.Name $Hostname $r.Path $r.info.CachedFreeSpace $r.Info.CachedTotalSpace
                        }
                        $outputAry += $outputObj
                }
                End {
                        $outputAry
                }
        }
        #endregion

        #region: Start BRHost Connection
        Connect-VBRServer -Server $BRHost
        #endregion

        #region: Collect and filter Repos
        [Array]$repoList = Get-VBRBackupRepository | Where-Object {$_.Type -ne "SanSnapshotOnly"}
        [Array]$scaleouts = Get-VBRBackupRepository -scaleout
        if ($scaleouts) {
                foreach ($scaleout in $scaleouts) {
                        $extents = Get-VBRRepositoryExtent -Repository $scaleout
                        foreach ($ex in $extents) {
                                $repoList = $repoList + $ex.repository
                        }
                }
        }
        #endregion

        #region: Build Report
        $RepoReport = $repoList | Get-vPCRepoInfo | Select-Object       @{Name="Repository Name"; Expression = {$_.Target}},
                                                                        @{Name="Host"; Expression = {$_.RepoHost}},
                                                                        @{Name="Path"; Expression = {$_.Storepath}},
                                                                        @{Name="Free (GB)"; Expression = {$_.StorageFree}},
                                                                        @{Name="Total (GB)"; Expression = {$_.StorageTotal}},
                                                                        @{Name="Free (%)"; Expression = {$_.FreePercentage}}
        forEach ($Repo in $RepoReport) {

                $r = [pscustomobject]@{
                        Name = $($Repo.'Repository Name')
                        'Free (%)' = $($Repo.'Free (%)')
                        'Free (GB)' = $($Repo.'Free (GB)')
                        'Total (GB)' =  $($Repo.'Total (GB)')
                        'Host' =  $($Repo.'Host')
                        'Path' =  $($Repo.'Path')
                    }

                New-PoshBotCardResponse -Title "$($Repo.'Repository Name'):" -Text ($r | Format-List -Property * | Out-String)
        }
        #endregion
}

Veeam Plugin for PoshBot - Get-VeeamRepositories Full

Get-VeeamJobSessions

function Get-VeeamJobSessions {
        <#
        .SYNOPSIS
        Get last Veeam Job Sessions
        .EXAMPLE
        !Get-VeeamJobSessions
        .EXAMPLE
        !Get-VeeamJobSessions --brhost <your BR Host>
        .EXAMPLE
        !JobSessions
        .EXAMPLE
        !VeeamJobSessions
        #>

        [PoshBot.BotCommand(
                Aliases = ('JobSessions', 'VeeamJobSessions'),
                Permissions = 'read'
        )]
        [cmdletbinding()]
        param(
                [Parameter(Position=0, Mandatory=$false)]
                        [string] $BRHost = "localhost"
        )

        #region: Start BRHost Connection
        Connect-VBRServer -Server $BRHost
        #endregion

        #region: Collect Sessions
        $Stats = (Get-VeeamAllStat).jobsessions
        #endregion

        #region: Build Report
        forEach ($Stat in $Stats) {

                                $r = [pscustomobject]@{
                                        JobName = $Stat.name
                                        JobType = $Stat.type
                                        HasRan = $Stat.hasRan
                                        JobStatus = $Stat.status
                                        CreationTime  = $Stat.creationTime
                                        EndTime  = $Stat.endTime
                                        VMsTotal = $Stat.vmstotal
                                        VMsSuccess = $Stat.vmssuccess
                                        VMsWarning = $Stat.vmswarning
                                        VMsError  = $Stat.vmserror
                                    }

                                New-PoshBotCardResponse -Title "Job '$($Stat.name)' Stats:" -Text ($r | Format-List -Property * | Out-String)
                                }
        #endregion
}

In meinem Veeam Plugin for PoshBot verwendete Klassen und Funktionen aus dem genialen PowerShell-VeeamAllStats Modul von Timothy Dewin:

class VeeamAllStatJobSessionVM {
    $name
    $status;
    $starttime;
    $endtime;
    $size;
    $read;
    $transferred;
    $duration;
    $details;
    VeeamAllStatJobSessionVM() {}
    VeeamAllStatJobSessionVM($name,$status,$starttime,$endtime,$size,$read,$transferred,$duration,$details) {
        $this.name = $name
        $this.status = $status;
        $this.starttime = $starttime;
        $this.endtime = $endtime;
        $this.size = $size;
        $this.read = $read;
        $this.transferred = $transferred;
        $this.duration  = $duration;
        $this.details = $details
    }
}

class VeeamAllStatJobSession {
    $name = "<no name>"
    $type = "<no type>";
    $description = "";
    $status = "<not run>";
    [System.DateTime]$creationTime='1970-01-01 00:00:00';
    [System.DateTime]$endTime='1970-01-01 00:00:00';
    [System.TimeSpan]$duration
    $processedObjects=0;
    $totalObjects=0
    $totalSize=0
    $backupSize=0
    $dataRead=0
    $transferredSize=0
    $dedupe=0
    $compression=0
    $details=""
    $vmstotal=0
    $vmssuccess=0
    $vmswarning=0
    $vmserror=0
    $allerrors=@{}
    [bool]$hasRan=$true
    [VeeamAllStatJobSessionVM[]]$vmsessions= @()
    VeeamAllStatJobSession() { }
    VeeamAllStatJobSession($name,$type,$description) {
        $this.name = $name
        $this.type = $type;
        $this.description =$description;
    }
    VeeamAllStatJobSession($name,$type,$description,$status,$creationTime,$endtime,$processedObjects,$totalObjects,$totalSize,$backupSize,$dataRead,$transferredSize,$dedupe,$compression,$details) {
        $this.name = $name
        $this.type = $type;
        $this.description =$description;
        $this.status = $status;
        $this.creationTime=$creationTime;
        $this.endTime=$endTime;
        $this.processedObjects=$processedObjects;
        $this.totalObjects=$totalObjects
        $this.totalSize=$totalSize
        $this.backupSize=$backupSize
        $this.dataRead=$dataRead
        $this.transferredSize=$transferredSize
        $this.dedupe=$dedupe
        $this.compression=$compression
        $this.details=$details
        $this.duration=$endTime-$creationTime
    }
}

class VeeamAllStatJobMain {
    $versionVeeam
    $server
    $serverString
    [VeeamAllStatJobSession[]]$jobsessions
    VeeamAllStatJobMain () {
        $this.jobsessions = @()
    }
}



function Get-VeeamAllStatJobSessionVMs {
    param(
        $session,
        [VeeamAllStatJobSession]$statjobsession
    )

    $tasks = $session.GetTaskSessions()

    foreach($task in $tasks) {
        $s = $task.status
        $vm = [VeeamAllStatJobSessionVM]::new(
            $task.Name,
            $s,
            $task.Progress.StartTime,
            $task.Progress.StopTime,
            $task.Progress.ProcessedSize,
            $task.Progress.ReadSize,
            $task.Progress.TransferedSize,
            $task.Progress.Duration,
            $task.GetDetails())

        if ($s -ieq "success") {
            $statjobsession.vmssuccess += 1
        } elseif ($s -ieq "warning" -or $s -ieq "pending" -or $s -ieq "none") {
            $statjobsession.vmswarning +=1
        } else {
            $statjobsession.vmserror += 1
        }
        if ($vm.details -ne "") {
            $statjobsession.allerrors[$task.Name]=$vm.details
        }
        $statjobsession.vmsessions += $vm
        $statjobsession.vmstotal+=1
    }
}

function Get-VeeamAllStatJobSession {
    param(
        $job,
        $session
    )
    $statjob = [VeeamAllStatJobSession]::new(
        $job.Name,
        $session.JobType,
        $job.Description,
        $session.Result,
        $session.CreationTime,
        $session.EndTime,
        $session.Progress.ProcessedObjects,
        $session.Progress.TotalObjects,
        $session.Progress.TotalSize,
        $session.BackupStats.BackupSize,
        $session.Progress.ReadSize,
        $Session.Progress.TransferedSize,
        $session.BackupStats.GetDedupeX(),
        $session.BackupStats.GetCompressX(),
        $session.GetDetails()
    )
    Get-VeeamAllStatJobSessionVMs -session $session -statjobsession $statjob

    if ($session.Result -eq "None" -and $session.JobType -eq "BackupSync") {
        if($session.State -eq "Idle" -and $statjob.vmserror -eq 0 -and $statjob.vmswarning -eq 0 -and $statjob.allerrors.count -eq 0 -and $statjob.details -eq ""  -and $session.EndTime -gt $session.CreationTime ) {
            if ($session.Progress.Percents -eq 100) {
                $statjob.Status="Success"
            }
        }
    }

    return $statjob
}

function Get-VeeamAllStatJobSessions {
    param(
        [VeeamAllStatJobMain]$JobMain
    )

    $allsessions = Get-VBRBackupSession
    $allorderdedsess = $allsessions | Sort-Object -Property CreationTimeUTC -Descending
    $jobs = get-vbrjob

    foreach ($Job in $Jobs) {
        $lastsession = $allorderdedsess | ? { $_.jobid -eq $Job.id } | select -First 1
        if ($lastsession -ne $null) {
           $JobMain.jobsessions += Get-VeeamAllStatJobSession -job $job -session $lastsession
        } else {
           $s = [VeeamAllStatJobSession]::new($job.Name,$job.type,$job.description)
           $s.hasRan = $false
           $JobMain.jobsessions += $s
        }
    }

}

function Get-VeeamAllStatServerVersion {
    param(
        [VeeamAllStatJobMain]$JobMain
    )
    $versionstring = "Unknown Version"

    $pssversion = (Get-PSSnapin VeeamPSSnapin -ErrorAction SilentlyContinue)
    if ($pssversion -ne $null) {
        $versionstring = ("{0}.{1}" -f $pssversion.Version.Major,$pssversion.Version.Minor)
    }

    $corePath = Get-ItemProperty -Path "HKLM:\Software\Veeam\Veeam Backup and Replication\" -Name "CorePath" -ErrorAction SilentlyContinue
    if ($corePath -ne $null) {
        $depDLLPath = Join-Path -Path $corePath.CorePath -ChildPath "Packages\VeeamDeploymentDll.dll" -Resolve -ErrorAction SilentlyContinue
        if ($depDLLPath -ne $null -and (Test-Path -Path $depDLLPath)) {
            $file = Get-Item -Path $depDLLPath -ErrorAction SilentlyContinue
            if ($file -ne $null) {
                $versionstring = $file.VersionInfo.ProductVersion
            }
        }
    }

    $servsession = Get-VBRServerSession
    $JobMain.versionVeeam = $versionstring
    $JobMain.server = $servsession.server
    $JobMain.serverString = ("Server {0} : Veeam Backup & Replication {1}" -f $servsession.server,$versionstring)
}

function Get-VeeamAllStat {
    $report = [VeeamAllStatJobMain]::new()

    Get-VeeamAllStatServerVersion -JobMain $report
    Get-VeeamAllStatJobSessions -JobMain $report
    return $report
}

function Get-HumanDataSize {
 param([double]$numc)
 $num = $numc+0
 $trailing= "","K","M","G","T","P","E"
 $i=0
 while($num -gt 1024 -and $i -lt 6) {
  $num= $num/1024
  $i++
 }
 return ("{0:f1} {1}B" -f $num,$trailing[$i])
}

function Get-HumanDate {
    param([DateTime]$t)
    return $t.toString("yyyy-MM-dd HH:mm:ss")
}

function Get-HumanDuration {
    param([System.TimeSpan]$d)
    return ("{0:D2}:{1:D2}:{2:D2}" -f ($d.Hours+($d.Days*24)),$d.Minutes,$d.Seconds)
}

Veeam Plugin for PoshBot - Get-VeeamJobSessions

Detailansicht eines Jobs:

Veeam Plugin for PoshBot - Get-VeeamJobSessions Full

Der Aufruf mit dem alternativen PoshBot Kommando und dem Alias für Get-VeeamSessions aus dem Veeam Plugin for PoshBot sieht in meinem Falls so aus:

Veeam Plugin for PoshBot - bender, JobSessions

Get-VeeamJobs

function Get-VeeamJobs {
        <#
        .SYNOPSIS
        Get Veeam Jobs
        .EXAMPLE
        !Get-VeeamJobs
        .EXAMPLE
        !Get-VeeamJobs --brhost <your BR Host>
        .EXAMPLE
        !Jobs
        .EXAMPLE
        !VeeamJobs
        #>

        [PoshBot.BotCommand(
                Aliases = ('Jobs', 'VeeamJobs'),
                Permissions = 'read'
        )]
        [cmdletbinding()]
        param(
                [Parameter(Position=0, Mandatory=$false)]
                [string] $BRHost = "localhost"
        )

        #region: Start BRHost Connection
        Connect-VBRServer -Server $BRHost
        #endregion

        #region: Collect Jobs
        [Array] $Jobs = Get-VBRJob
        #endregion

        #region: Build Report
        $report = @()
        forEach ($Job in $Jobs) {

                $object = [pscustomobject]@{
                        Name = $Job.Name
                        JobType = $Job.JobType
                    }
                $report += $object
        }
        New-PoshBotCardResponse -Title "Veeam Jobs:" -Text ($report | Format-List -Property * | Out-String)
        #endregion
}

Veeam Plugin for PoshBot - Get-VeeamJobs

Start-VeeamQuickBackup

function Start-VeeamQuickBackup {
    <#
    .SYNOPSIS
    STart Veeam Quick Backup
    .EXAMPLE
    !Start-VeeamQuickBackup --ViEntity <VM Name>
    .EXAMPLE
    !Start-VeeamQuickBackup --ViEntity <VM Name> --brhost <your BR Host>
    .EXAMPLE
    !VuickBackup --ViEntity <VM Name>
    .EXAMPLE
    !VeeamQuickBackup --ViEntity <VM Name>
    #>

    [PoshBot.BotCommand(
        Aliases = ('QuickBackup', 'VeeamQuickBackup'),
        Permissions = 'write'
    )]
    [CmdletBinding()]
        param(
            [Parameter(Mandatory=$true, Position=0)]
            [ValidateNotNullorEmpty()]
            [String]$ViEntity,
            [Parameter(Mandatory=$false, Position=1)]
            [ValidateNotNullorEmpty()]
            [string] $BRHost = "localhost"
        )

    #region: Load PSSnapIn
    if ( (Get-PSSnapin -Name VeeamPSSnapin -ErrorAction SilentlyContinue) -eq $null ) {
        Add-PSsnapin VeeamPSSnapin
    }
    #endregion

    #region: Start BRHost Connection
    Connect-VBRServer -Server $BRHost
    #endregion

    if ($VeeamVm = Find-VBRViEntity -Name $ViEntity) {

        $Result = Start-VBRQuickBackup -VM $VeeamVm -Wait

        if ($Result) {

            #region: Build Report
            $report = @()
            $object = [pscustomobject]@{
                JobName = $Result.JobName
                Result = $Result.Result
                CreationTime = $Result.CreationTime
                EndTime = $Result.EndTime
                }
            $report += $object
            New-PoshBotCardResponse -Title "Veeam Quickbackup Result:" -Text ($report | Format-List -Property * | Out-String)
            #endregion
        }

        if ($Result.Result -eq "Failed") {
            Throw "Quick Backup Failed. See Veeam B&R Console for more details!"
        }

    }
    else {
        Throw "No ViEntity '$ViEntity' found!"
    }

}

Veeam Plugin for PoshBot - Start-VeeamQuickBackup

Install Veeam Plugin for PoshBot

Um mein Veeam Plugin for PoshBot ganz unkompliziert zur Verfügung zu stellen habe ich es mit dem entsprechenden Tag in der PowerShell Gallery veröffentlicht. Alle verfügbaren Plugins lassen sich mit dem Kommando

!find-plugin
 ganz einfach auflisten und mit
!install-plugin
 auch direkt installieren.

Veeam Plugin for PoshBot - Install-Plugin

Nach der Installation steht auch die Hilfe zu dem Plugin zur Verfügung. Besonders interessant sind hierbei auch die Aliase für die Kommandos, damit ist die Eingabe (besonders am Smartphone) doch etwas flotter.

Veeam Plugin for PoshBot - Plugin Help

Ebenso kann die Hilfe für die einzelnen Kommandos des Plugins angezeigt werden und auch die notwendigen Rechte geprüft werden, dazu aber später mehr.

Veeam Plugin for PoshBot - Command Help

Mit dem Slack Befehl 

!help poshbot.veeam:Get-VeeamJobSessions --detailed
 kann die vollständige Hilfe für das Kommando, inklusive Beispielen aufgerufen werden.

Die Ausführung der Kommandos des Plugins ist dank Access Control nochmal eine andere Sache:

Veeam Plugin for PoshBot - Not authorized

Nachdem der Slack User der passenden Gruppe zugeordnet wurde, klappt es aber auch mit den Kommandos:

Veeam Plugin for PoshBot - Authorized

Die Gruppe habe ich vorab mit den entsprechenden Befehlen vorbereitet und die Rechte für das Veeam Plugin for PoshBot vergeben:

!New-Group veeamadmins
!New-Role veeamadmins
!Add-GroupRole veeamadmins veeamadmins

!Add-RolePermission veeamadmins poshbot.veeam:read
!Add-RolePermission veeamadmins poshbot.veeam:write

Weiterentwicklung Veeam Plugin for PoshBot

Wie so viele meiner Projekte ist auch dieses im Status „Work in Progress“ und ich würde mich über etwas Input freuen welche Funktionen praktisch oder hilfreich wären.

Ich bin dankbar über jeden Kommentar zu diesem Beitrag bzw. Issue oder Enhancement Request in dem dazugehörigen  GitHub Projekt.

The post Veeam Plugin for PoshBot chat bot appeared first on my cloud-(r)evolution.

Flattr this!

Veeam Backup & Replication 9.5 Update 3 Compatibility

$
0
0

Veeam hat vor kurzem mit dem Veeam Backup & Replication 9.5 Update 3 eine sehr umfangreiche Aktualisierung und Erweiterung Ihres Kernproduktes veröffentlicht. Um die Funktion meiner kleiner Veeam Helferlein und Tools sicherzustellen habe ich mich an den Veeam Backup & Replication 9.5 Update 3 Compatibility Check dieser gemacht.

Veeam Backup & Replication 9.5 Update 3 Compatibility

Zu dem Updatevorgang selbst kann ich nur sagen, dass es in meiner Lab Umgebung zu keinerlei Problemen kam. Weder mit Veeam Backup & Replication noch mit dem Veeam Enterprise Manager. Mein VMware vCenter 6.5 Update 1 sowie der NetApp Simulator 9.1 funktionieren nach dem Update ebenfalls weiterhin problemlos.

Was steck alles in 9.5 Update 3

Wie den Release Notes zu entnehmen ist, ist die wichtigste Neuerung das Built-in agent management. Mit dieser Erweiterung der Funktionalität von Veeam Backup & Replication können nun Windows und Linux Backup Agents über die Konsole ausgebracht und Verwaltet werden. Ganz nebenbei wird damit auch das Sicherungsproblem von Microsoft Clustern auf VMware vSphere gelöst. Diese können nicht per Snapshot gesichert werden, fielen also bisher aus der Veeam Backup & Replication Sicherung heraus (auch Veeam Standalone Agent war nicht unterstützt).

Sehr wichtig ist auch die Unterstützung neuer Plattformen wie VMware Cloud on AWS, VMware vCloud Director 9.0 und Microsoft SQL Server 2017.

Weitere Beiträge zu dem Release:

Veeam Backup & Replication 9.5 Update 3 Compatibility

Da es sich eben um ein sehr umfangreiches Update handelt, wollte ich sicherstellen, dass auch die wichtigsten meiner Skripte und Tools weiter funktionieren.

Name Blog Post GitHub Project Compatibility
Veeam PRTG Sensor

März 21, 2016

Latest Ja
Veeam PoshBot Plugin November 27, 2017 Latest Ja
Veeam vSphere Interactions September 7, 2017 Latest Ja
Veeam Backup Validator Pester November 13, 2017 Ja

Bitte beachten:

Alle diese Tools greifen auf das Veeam PowerShell SnapIn zu. Die Verbindung zum Veeam Server funktioniert nur mit der exakt passenden Version. Falls also die Skripte nicht auf dem Veeam Server selbst ausgeführt werden, bitte nach dem Update auch die weiteren Konsolen und PowerShell SnapIn`s aktualisieren.

Alle meine jüngeren Veeam Projekte funktionieren also noch wie gehabt mit dem Veeam Backup & Replication 9.5 Update 3. Dennoch stehen bald ein paar weitere Tests und Anpassungen an:

Im neuen Jahr sind also schon ein paar Blog Post gesichert.

The post Veeam Backup & Replication 9.5 Update 3 Compatibility appeared first on my cloud-(r)evolution.

Flattr this!

VMware vCloud Director Provider for Terraform

$
0
0

HashiCorp hat mit Ihrem Produkt Terraform ein sehr mächtiges Werkzeug im Bereich Infrastructure as Code im Portfolio. Mit dessem Artikel möchte ich einen Einstieg bieten in die Nutzung eines der vielen Provider und zwar den VMware vCloud Director Provider for Terraform.

VMware vCloud Director Provider for Terraform

Terraform Installieren

Unter Windows muss lediglich die Terraform.exe in einen beliebigen Ordner gepackt werden und dieser der Umgebungsvariable Path hinzugefügt werden. Mehr Infos finden sich im Getting Started Guide.

 vCloud Director Provider for Terraform - PATH

Überprüfen der Installation

Zur Überprüfung der Installation kann nach dem Anpassen der Umgebungsvariablen einfach ein terraform Kommando in der CMD aufgerufen werden.

C:\>terraform
Usage: terraform [--version] [--help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
    apply              Builds or changes infrastructure
    console            Interactive console for Terraform interpolations
    destroy            Destroy Terraform-managed infrastructure
    env                Workspace management
    fmt                Rewrites config files to canonical format
    get                Download and install modules for the configuration
    graph              Create a visual graph of Terraform resources
    import             Import existing infrastructure into Terraform
    init               Initialize a Terraform working directory
    output             Read an output from a state file
    plan               Generate and show an execution plan
    providers          Prints a tree of the providers used in the configuration
    push               Upload this Terraform module to Atlas to run
    refresh            Update local state file against real resources
    show               Inspect Terraform state or plan
    taint              Manually mark a resource for recreation
    untaint            Manually unmark a resource as tainted
    validate           Validates the Terraform files
    version            Prints the Terraform version
    workspace          Workspace management

All other commands:
    debug              Debug output management (experimental)
    force-unlock       Manually unlock the terraform state
    state              Advanced state management

vCloud Director Provider for Terraform Basics

Ordnerstruktur

Ich habe für mich den Weg gefunden, für jedes Projekt bzw. für jede Applikation einen eigenen Unterordner innerhalb eines GitHub Repository anzulegen. Die Applikation ist in den Beispiel „Basics“.

<Repository Root>
│   .gitignore
│   README.md
│
├───Basics
│   │   00 Config.tf
│   │   01 Network.tf
│   │   02 vApp.tf
│   │   03 Firewall.tf
│   │   terraform.tfstate
│   │   terraform.tfstate.backup
│   │   vcd.tfvars
│   │
│   └───.terraform
│       └───plugins
│           └───windows_amd64
│                   lock.json
│                   terraform-provider-vcd_v1.0.0_x4.exe
│
└───Media
        terraform-vcd-logo.png

Wie man an dem Beispiel sehen kann erzeugt Terraform in dem Arbeitsverzeichnis des Projekts einige weitere Files und eines davon ist von besonderer Relevanz:

  • terraform.tfstate (lokales State File)
  • terraform.tfstate.backup
  • .terraform
    • plugins

Der Inhalt des State Files kann entweder mit terraform show aufgerufen werden oder einfach der Texteditor eingesehen werden.

Ich habe hier alleine an diesem kleinen Terraform Projekt gearbeitet, wenn jedoch später geplant wird im Team an einem Projekt zu arbeiten, sollte unbedingt über die Konfiguration eines Remote Backends nachgedacht werden. Damit kann dann der Terraform State zum Beispiel in einem AWS S3 Bucket abgelegt und das State Locking über eine AWS DynamoDB Table abgehandelt werden.

Falls das Projekt auch bei dir ein GitHub (oder ähnliches) Repository werden soll bei dem das State File lokal liegen, unbedingt auf eine sinnvolle .gitignore achten und niemals sensible Daten (Passwörter, etc.) direkt in die .tf Files schreiben!

# =========================
# App Files
# =========================

# Terraform
# =========================

# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# .tfvars files
*.tfvars

Das es wirklich Sinn macht, seine Terraform Projekte in einer Versioncontrol (GIT, etc) zu verwalten sieht man an diesem kleinen Beispiel:

 vCloud Director Provider for Terraform - Git History

Initialisierung

Zur Basis-Initialisierung ist erst einmal nur die Provider Konfiguration notwendig. Diese lege ich in jedem Fall in ein separates .tf File.

Note:

Auch wenn später die Variablen durch ein zusätzlichen *.tfvars File gefüllt werden, müssen diese dennoch erst einmal initialisiert werden.

Basis Provider Konfiguration:

# VMware vCloud Director Provider Variables (Blank)
variable "vcd_user" {
    description = "vCD Tenant User"
}
variable "vcd_pass" {
   description = "vCD Tenant Password"
}
variable "vcd_org" {
   description = "vCD Tenant Org"
}
variable "vcd_url" {
   description = "vCD Tenant URL"
}
variable "vcd_vdc" {
   description = "vCD Tenant VDC"
}
variable "vcd_max_retry_timeout" {
   description = "Retry Timeout"
   default = "240"
}

#  VMware vCloud Director Provider Configuration
provider "vcd" {
  user                 = "${var.vcd_user}"
  password             = "${var.vcd_pass}"
  org                  = "${var.vcd_org}"
  url                  = "${var.vcd_url}"
  vdc                  = "${var.vcd_vdc}"
  max_retry_timeout    = "${var.vcd_max_retry_timeout}"
}

Mit dieser Provider Konfiguration kann Terraform nun initialisiert werden und wenn nötig wird der VMware vCloud Director Provider installiert bzw. wird in dem aktuellen Arbeitsbereich bereitgestellt.

 vCloud Director Provider for Terraform - init

Nach der erfolgreichen Initialisierung mit der VMware vCloud Director Provider for Terraform Konfiguration, kann nun auch diese Version überprüft werden.

 vCloud Director Provider for Terraform - provider version

Planung und Validierung

In der aktuellen Konfiguration macht die Planung einer Änderung mir dem Kommando plan noch nicht viel Sinn, man kann jedoch sehr gut sein Variables File und die Verbindung zur Umgebung damit überprüfen.

*.tfvars File für die Provider Config:

vcd_user = "******"
vcd_org = "******"
vcd_vdc = "******"
vcd_url = "https://******/api"

 vCloud Director Provider for Terraform - plan

Note:

Ich habe hier explizit an Var-File angeben, das ist aber nicht zwingend notwendig. Die Logik verhält sich wie folgt:

If a terraform.tfvars or any .auto.tfvars files are present in the current directory, they will be automatically loaded. terraform.tfvars is loaded first and the .auto.tfvars files after in alphabetical order. Any files specified by -var-file override any values set automatically from files in the working directory.

Mit dem Kommando validate kann alternativ (und unabhängig von der Verbindung) auch nur die Syntax der Files geprüft werden.

 vCloud Director Provider for Terraform - validate

vCloud Director Provider for Terraform Provisioning

Simples Netzwerk und neue vApp anlegen

Um im VMware vCloud Director mit Terraform ein neues Organisationsnetzwerk und eine vApp aus einem Template zu erstellen sind zwei zusätzliche Ressourcen Konfigurationen notwendig, vcd_network und vcd_vapp. Um sicherzustellen, dass die Konfigurationen auch in der korrekten Reihenfolge abgearbeitet werden, habe ich eine Nummerierung zu den einzelnen Files hinzugefügt (die Übersicht beim plan und apply Kommando zeigt aber nicht umgedingt die korrekte Reihenfolge an).

Orderstruktur:

<Project Folder>
│   00 Config.tf
│   01 Network.tf
│   02 vApp.tf
│   terraform.tfstate
│   terraform.tfstate.backup
│   vcd.tfvars
│
└───.terraform
    └───plugins
        └───windows_amd64
                lock.json
                terraform-provider-vcd_v1.0.0_x4.exe

Ressourcen Konfigurationen:

# VMware vCloud Director Network Variables (Blank)
variable "vcd_edge" {
    description = "vCD Tenant Edge Gateway"
}

# VMware vCloud Director Network Resource Definition
resource "vcd_network" "tf-net" {
  name         = "my-tf-net"
  edge_gateway = "${var.vcd_edge}"
  gateway      = "172.20.0.1"

  static_ip_pool {
    start_address = "172.20.0.100"
    end_address   = "172.20.0.200"
  }
}

# VMware vCloud Director vApp Variables (Blank)
variable "vcd_catalog" {
    description = "vCD Catalog Name"
}

# VMware vCloud Director vApp Ressource Definition
resource "vcd_vapp" "tf-vapp" {
  name          = "tf-vapp"
  catalog_name  = "${var.vcd_catalog}"
  template_name = "Ubuntu 16.04 LTS"
  memory        = 2048
  cpus          = 1

  network_name = "${vcd_network.tf-net.name}"

}

In der Ressourcen Definition für die vApp ist auch zu sehen, wie auf vorab definierte Ressourcen referenziert werden kann (network_name = „${vcd_network.tf-net.name}“). Mit der neuen Konstellation macht es nun schon wesentlich mehr Sinn einen eine Planung durchzuführen.

Note:

Für den produktiven Einsatz würde ich unbedingt empfehlen, erst eine leere vApp Ressource zu erstellen und dann VMs hinzuzufügen (siehe auch weiter unten). Mit der vApp VM Ressource funktioniert die Gast-Anpassungen wesentlich besser.

Beispiel:

resource "vcd_vapp" "tf-vapp-neu" {
  name          = "tf-vapp-neu"
  network_name = "${vcd_network.tf-net.name}"

}

resource "vcd_vapp_vm" "tf-vapp-neu-add-1" {
  vapp_name     = "${vcd_vapp.tf-vapp-neu.name}"
  name          = "tf-vapp-neu-add-1"
  catalog_name  = "${var.vcd_catalog}"
  template_name = "Ubuntu 16.04 LTS"
  memory        = 2048
  cpus          = 1

  network_name = "${vcd_network.tf-net.name}"
  ip           = "172.20.0.110"
}

 vCloud Director Provider for Terraform - plan network and vapp

Da das gewünschte Ergebnis simuliert wurde, kann die Konfiguration mit dem Kommando apply nun auch angewendet werden.

 vCloud Director Provider for Terraform - apply network and vapp

Nach erneuter Bestätigung werden die Änderungen durch den vCloud Director Provider for Terraform durchführt.

 vCloud Director Provider for Terraform - process apply network and vapp

In-Place Update der vApp VM

Eine Änderung der vCPU Anzahl von vApp VMs ist zum Beispiel ein In-Place Update, was bedeutet die Ressource muss nicht neu bereitgestellt werden.

 vCloud Director Provider for Terraform - apply update in-place vapp

Weitere VMs zur vApp hinzufügen

Die neuen vApp Ressourcen Definition sieht nun zwei weitere VMs in der bestehenden vApp vor. Diese werden über die Ressource vcd_vapp_vm definiert und erhalten fixe IPs aus dem Bereich des static_ip_pool. Wird keine IP für die VM konfiguriert steht die Netzwerkkarte auf DHCP.

# VMware vCloud Director vApp Variables (Blank)
variable "vcd_catalog" {
    description = "vCD Catalog Name"
}

# VMware vCloud Director vApp Ressource Definition
resource "vcd_vapp" "tf-vapp" {
  name          = "tf-vapp"
  catalog_name  = "${var.vcd_catalog}"
  template_name = "Ubuntu 16.04 LTS"
  memory        = 2048
  cpus          = 2

  network_name = "${vcd_network.tf-net.name}"
}

resource "vcd_vapp_vm" "tf-vapp-add-1" {
  vapp_name     = "${vcd_vapp.tf-vapp.name}"
  name          = "tf-vapp-add-1"
  catalog_name  = "${var.vcd_catalog}"
  template_name = "Ubuntu 16.04 LTS"
  memory        = 2048
  cpus          = 1

  ip           = "172.20.0.100"
}

resource "vcd_vapp_vm" "tf-vapp-add-2" {
  vapp_name     = "${vcd_vapp.tf-vapp.name}"
  name          = "tf-vapp-add-2"
  catalog_name  = "${var.vcd_catalog}"
  template_name = "Ubuntu 16.04 LTS"
  memory        = 2048
  cpus          = 1

  ip           = "172.20.0.101"
}

Warning:

Sollen mehrer VMs eine vApp hinzugefügt werden bitte unbeding diesen GitHub Issue beachten.

Workaround: 

terraform apply -parallelism=1

 vCloud Director Provider for Terraform - apply additional vapp vms

Die finale vApp sieht nun im VMware vCloud Director so aus:

 vCloud Director Provider for Terraform - vcd vapp

Neue Firewall Regel hinzufügen

In einem weiteren Terraform File habe ich eine Firewall Ressourcen Definition festgelegt. Es sollen zwei Allow-Regeln für das neue Netz erzeugt werden. Falls bereits existierende Regeln vorhanden sind, werden diese nicht angefasst.

Warning:

Die Dokumentation für die Ressource vcd_firewall_rules ist leider nicht ganz korrekt (GitHub Issue ist bereits erstellt worden).

Falsch: default_action = „deny“

Richtig: default_action = „drop“


# VMware vCloud Director Firewall  Ressource Definition
resource "vcd_firewall_rules" "fw" {
  edge_gateway   = "${var.vcd_edge}"
  default_action = "drop"

  rule {
    description      = "allow-http"
    policy           = "allow"
    protocol         = "tcp"
    destination_port = "80"
    destination_ip   = "any"
    source_port      = "any"
    source_ip        = "172.20.0.0/24"
  }

  rule {
    description      = "allow-https"
    policy           = "allow"
    protocol         = "tcp"
    destination_port = "443"
    destination_ip   = "any"
    source_port      = "any"
    source_ip        = "172.20.0.0/24"
  }
}

 vCloud Director Provider for Terraform - apply firewall rules

Die Ressource vcd_firewall_rules kann ebenso wie in einem vorherigen Beispiel mit Übergabewerten aus anderen Ressourcen arbeiten. Dadurch ist wesentlich weniger Pflege von IPs bei komplexen Konstrukten in den Firewall Regelwerken notwendig.

Hier ein Beispiel für eine zusätzliche Regel:

# VMware vCloud Director Firewall  Ressource Definition
resource "vcd_firewall_rules" "fw" {
  edge_gateway   = "${var.vcd_edge}"
  default_action = "drop"

  rule {
    description      = "allow-http"
    policy           = "allow"
    protocol         = "tcp"
    destination_port = "80"
    destination_ip   = "any"
    source_port      = "any"
    source_ip        = "172.20.0.0/24"
  }

  rule {
    description      = "allow-https"
    policy           = "allow"
    protocol         = "tcp"
    destination_port = "443"
    destination_ip   = "any"
    source_port      = "any"
    source_ip        = "172.20.0.0/24"
  }

  rule {
    description      = "allow-ntp"
    policy           = "allow"
    protocol         = "udp"
    destination_port = "123"
    destination_ip   = "any"
    source_port      = "any"
    source_ip        = "${vcd_vapp_vm.tf-vapp-add-1.ip}"
  }
}

VMware vCloud Director Provider for Terraform - additional firewall rule

Ressourcen wieder löschen

Wichtiger Teil des Lebenszyklus der bereitgestellten Ressourcen ist natürlich auch das Löschen dieser, dafür kennt Terraform das Kommando destroy. Alle durch Terraform verwaltetet Ressourcen werden damit wieder in einer sinnvollen Reihenfolge gelöscht.

Warning:

Sollen mehrer VMs eine vApp gelöscht werden bitte unbedingt ebenfalls den Schalter 

-parallelism=1
 nutzen.

VMware vCloud Director Provider for Terraform - destroy

vCloud Director Provider for Terraform Fazit

Terraform ist in jedem Fall ein super nützliches Tool und der VMware vCloud Director Provider kann in der Version 1.0 auch bereits für viele Grundlegende Dinge verwendet werden. Dennoch hat speziell der Provider noch enorm Verbesserungspotential.

Ich kann daher um das Produkt weiter auszubauen nur alle Nutzer und Interessierten anhalten die Probleme und Verbesserungswünsche in dem GitHub Provider Repository als Issue einzukippen sowie sich in der Community einzubringen. Der Entwurf für den Plan für die Version 2 sieht auf jeden Fall schon vielversprechend aus.

vCloud Director Provider for Terraform Beispiele

Meine gesamten Beispiele habe ich in einem GitHub Repository zusammengefasst:

VMware-vCD-Terraform

The post VMware vCloud Director Provider for Terraform appeared first on my cloud-(r)evolution.

Flattr this!

Viewing all 153 articles
Browse latest View live