<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Automation Archives - VirtJunkie</title>
	<atom:link href="/category/automation/feed/" rel="self" type="application/rss+xml" />
	<link>/category/automation/</link>
	<description>Virtualization, Automation, and anything else that might be on my mind</description>
	<lastBuildDate>Mon, 15 Aug 2022 13:27:41 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.5.5</generator>

<image>
	<url>/wp-content/uploads/2020/04/cropped-vj4-150x150.png</url>
	<title>Automation Archives - VirtJunkie</title>
	<link>/category/automation/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Authenticate to vRealize Orchestrator API using PowerShell</title>
		<link>/2022/08/15/authenticate-to-vrealize-orchestrator-api-using-powershell/</link>
					<comments>/2022/08/15/authenticate-to-vrealize-orchestrator-api-using-powershell/#respond</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Mon, 15 Aug 2022 13:27:40 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">https://www.virtjunkie.com/?p=1479</guid>

					<description><![CDATA[<p>I&#8217;m working on a project that requires direct interaction with the vRO API from a third party system. Maybe I&#8217;m getting less effective at using Google in my old age, but I had a heck of a time finding good solid code for authenticating to the API using anything, including PowerShell. Typically I&#8217;d use Invoke-vRARestMethod [&#8230;]</p>
<p>The post <a href="/2022/08/15/authenticate-to-vrealize-orchestrator-api-using-powershell/">Authenticate to vRealize Orchestrator API using PowerShell</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><br></p>



<div class="wp-block-media-text alignwide has-media-on-the-right is-stacked-on-mobile is-vertically-aligned-top" style="grid-template-columns:auto 36%"><figure class="wp-block-media-text__media"><img fetchpriority="high" decoding="async" width="925" height="1024" src="https://www.virtjunkie.com/wp-content/uploads/2022/08/image-925x1024.png" alt="" class="wp-image-1481 size-full" srcset="/wp-content/uploads/2022/08/image-925x1024.png 925w, /wp-content/uploads/2022/08/image-271x300.png 271w, /wp-content/uploads/2022/08/image-768x850.png 768w, /wp-content/uploads/2022/08/image-1388x1536.png 1388w, /wp-content/uploads/2022/08/image.png 1641w" sizes="(max-width: 925px) 100vw, 925px" /></figure><div class="wp-block-media-text__content">
<p>I&#8217;m working on a project that requires direct interaction with the vRO API from a third party system. Maybe I&#8217;m getting less effective at using Google in my old age, but I had a heck of a time finding good solid code for authenticating to the API using anything, including PowerShell. </p>



<p>Typically I&#8217;d use <a rel="noreferrer noopener" href="https://jakkulabs.github.io/PowervRA/functions/Invoke-vRARestMethod/" target="_blank">Invoke-vRARestMethod </a>from <a rel="noreferrer noopener" href="https://github.com/jakkulabs/PowervRA" target="_blank">PowerVRA</a> for this, but unfortunately I had some additional requirements that mandate me using a bearer token.</p>



<p>As a point of reference, you can view all of of the available APIs for vRealize Automation by navigating to this url: https://{your-vra-url}/automation-ui/api-docs/. We&#8217;ll be working with the &#8220;Orchestrator&#8221; API</p>
</div></div>



<p>The function below will return a bearer token, which you can use in future API calls to vRA.</p>



<script src="https://gist.github.com/jonhowe/36304d54b77e794427534b8b38f0bd0d.js"></script>



<p>Param&#8217;s:<br>Line 3: vra_server &#8211; the fqdn of your vRA 8 instance<br>Line 4: password &#8211; password associated with your vRA 8 account used to authenticate. As mentioned, please be smart here. Plantext passwords are bad.<br>Line 5: username &#8211; Unlike vRA 7, vRA 8 needs you to split your username and domain apart. For example, in vRA 7 you&#8217;d authenticate using the username jon.smith@rainpole.com, where in vRA 8 you authenticate using just the username jon.smith<br>Line 6: domain &#8211; This is where the domain goes (Example: rainpole.com)<br><br>Lines 14-24: We&#8217;re setting the body up to be included in the rest request. There&#8217;s some special formatting required so we&#8217;re using the replace method to modify the string.<br><br>Line 27: Build a simple variable with the URI used for authentication. More can be found on this in the API documentation mentioned above.<br><br>Lines 29-35: Make the API call, build the bearer token (essentially add the word &#8220;Bearer &#8221; to the beginning of the authentication token), and return it.</p>



<p>Short and sweet. I&#8217;ll be adding some more snippets and problems in the future.</p>
<p>The post <a href="/2022/08/15/authenticate-to-vrealize-orchestrator-api-using-powershell/">Authenticate to vRealize Orchestrator API using PowerShell</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2022/08/15/authenticate-to-vrealize-orchestrator-api-using-powershell/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Configure vROps To Send Alerts to OpsGenie and Microsoft Teams</title>
		<link>/2021/07/23/vrops-opsgenie-production-setup/</link>
					<comments>/2021/07/23/vrops-opsgenie-production-setup/#comments</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Fri, 23 Jul 2021 18:35:59 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Hashicorp]]></category>
		<category><![CDATA[InfrastructureAsCode]]></category>
		<category><![CDATA[Packer]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[vExpert]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">https://www.virtjunkie.com/?p=1431</guid>

					<description><![CDATA[<p>Packer, Photon, Python, Flask, WSGI, vROps. Holy smokes folks.. I&#8217;m not sure I could make a more click-bait-y post if I tried! I recently took a position at a new company and had the opportunity to stand up a greenfield environment. Part of this environment was obviously configuring monitoring. Since we&#8217;re pretty heavily tied to [&#8230;]</p>
<p>The post <a href="/2021/07/23/vrops-opsgenie-production-setup/">Configure vROps To Send Alerts to OpsGenie and Microsoft Teams</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Packer, Photon, Python, Flask, WSGI, vROps. Holy smokes folks.. I&#8217;m not sure I could make a more click-bait-y post if I tried!</p>



<p>I recently took a position at a new company and had the opportunity to stand up a greenfield environment. Part of this environment was obviously configuring monitoring. Since we&#8217;re pretty heavily tied to VMware here, we&#8217;re using vROps for our monitoring. For escalation of alerts, we&#8217;re using OpsGenie, and for normal collaboration we&#8217;re using Teams. Unfortunately, vROps versions older than 8.4 do not support sending alerts to OpsGenie or Teams out of the box. Fortunately, we can still get this working with a bit of work.</p>



<span id="more-1431"></span>



<h2 class="wp-block-heading">Overview</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-1 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:66.66%">
<p class="has-black-color has-pale-cyan-blue-background-color has-text-color has-background">Update &#8211; Starting in vROps 8.4 you can use the webhook plugin that is delivered with vROps to accomplish this. <a href="https://docs.vmware.com/en/vRealize-Operations-Manager/8.4/com.vmware.vcom.core.doc/GUID-9314313D-1DE6-4160-AEFD-76B23AB5DAD9.html" target="_blank" rel="noreferrer noopener"><strong>LINK</strong></a></p>



<p>While vROps does have the ability to send outgoing notifications via REST API, it doesn&#8217;t have the ability to let you customize what fields are sent, or how they are formatted. Because of this limitation, <a rel="noreferrer noopener" href="https://github.com/vmw-loginsight/webhook-shims/graphs/contributors" target="_blank">some very thoughtful folks</a> created <a rel="noreferrer noopener" href="https://github.com/vmw-loginsight/webhook-shims" target="_blank">a project called webhook-shims</a>. This is essentially a Python Flask project that accepts web requests, translates them, then forwards the correctly formatted request off to whatever system you want notifications sent to.</p>



<p>This project hasn&#8217;t been updated in over 3 years, has a number of pending PR&#8217;s and Issues, so my spidey sense says it&#8217;s likely dead. So please be smart about how and where you use this, and consider the implications of running this in production. That said, from a functional standpoint, it seems to work well, and in the rest of this post I&#8217;ll go over how to set this up to run in a production fashion.</p>



<p>The list to the right are the applications that the project supports, and the bold items are what I&#8217;ll show example configuration for.</p>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow" style="flex-basis:33.33%">
<ul><li>bigpanda</li><li>bugzilla</li><li>groove</li><li>hipchat</li><li>jenkins</li><li>jira</li><li>kafkatopic</li><li><strong>opsgenie</strong></li><li>pagerduty</li><li>pivotaltracker</li><li>pushbullet</li><li>servicenow</li><li>slack</li><li>socialcast</li><li>travisci</li><li>vrealizeorchestrator</li><li>zendesk</li><li>moogsoft</li><li><strong>msteams</strong></li></ul>
</div>
</div>



<h2 class="wp-block-heading">Approach</h2>



<p>We&#8217;ll be running this whole project using Photon OS 4.</p>



<p>While we could simply run the python script in a <a rel="noreferrer noopener" href="https://www.gnu.org/software/screen/" target="_blank">screen</a>, <a rel="noreferrer noopener" href="https://github.com/tmux/tmux/wiki" target="_blank">tmux</a>, or similar session, but there are serious limitations in doing that. Admittedly, my python isn&#8217;t as strong as some of my other scripting languages, but after a bit of digging, it became clear that things like security, performance, and monitoring are either limited or unavailable if we do this. We&#8217;ll use a WSGI server called <a rel="noreferrer noopener" href="https://gunicorn.org/" target="_blank">Gunicorn</a> to run the python script, and use systemd to create a socket and service, and finally, use Nginx to connect directly to the socket. Whew! Even just reading that after completing this entire project feels like a lot, but don&#8217;t worry. As always, I&#8217;ll explain each step in detail and give you code to create this project.</p>



<h2 class="wp-block-heading">Create Photon Packer Template</h2>



<p>If you don&#8217;t know this about me by now, I&#8217;m a huge fan of packer. As such, we&#8217;ll be using it to create a template. You can find the source code for this packer template on <a href="https://github.com/jonhowe/Virtjunkie.com/tree/master/Packer/PhotonOS4" data-type="URL" data-id="https://github.com/jonhowe/Virtjunkie.com/tree/master/Packer/PhotonOS4">my website&#8217;s github repository</a></p>



<p>To get a local copy, run the following command:</p>



<p>
			<span id="urvanov-syntax-highlighter-667f6dc94ee9e426691471" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-e">git </span><span class="crayon-r">clone</span><span class="crayon-h"> </span><span class="crayon-v">https</span><span class="crayon-o">:</span><span class="crayon-o">/</span><span class="crayon-o">/</span><span class="crayon-v">github</span><span class="crayon-e">.com</span><span class="crayon-o">/</span><span class="crayon-v">jonhowe</span><span class="crayon-o">/</span><span class="crayon-v">Virtjunkie</span><span class="crayon-e">.com</span><span class="crayon-e">.git</span></span></span></p>



<p>You can find all source code in the directory Virtjunkie.com/Packer/PhotonOS4.</p>



<h3 class="wp-block-heading">Create Custom ISO</h3>



<p>Unfortunately, Photon OS, even in v4, doesn&#8217;t support providing the kickstart file via CD-ROM or floppy (see <a rel="noreferrer noopener" href="https://github.com/vmware/photon/issues/1113" target="_blank">Issue#1113</a>, <a rel="noreferrer noopener" href="https://github.com/vmware/photon/issues/798" data-type="URL" data-id="https://github.com/vmware/photon/issues/798" target="_blank">Issue#798)</a>.  Unfortunately, this means that if we want (or need) to use the vsphere-iso builder, we&#8217;ll need to create an ISO with the kickstart file embedded. <a rel="noreferrer noopener" href="https://vmware.github.io/photon/docs/user-guide/working-with-kickstart/#building-an-iso-with-a-kickstart-config-file" target="_blank">I&#8217;m not going to duplicate documentation, so here&#8217;s the official documentation from VMware on how to add a kickstart file.</a></p>



<p>Instead of using the sample my_ks.cfg file provided in the ISO, use the version below.</p>



<p class="has-black-color has-luminous-vivid-amber-background-color has-text-color has-background">IMPORTANT: Ensure that you replace [yourpassword] with your actual password</p>



<script src="https://gist.github.com/jonhowe/7da290c7cfd660ddb220c96349d0f024.js"></script>



<h3 class="wp-block-heading">Use Packer To Create vSphere Template</h3>



<p class="has-luminous-vivid-amber-background-color has-background">IMPORTANT: Ensure that the password assigned to &#8220;root_password&#8221; in Virtjunkie.com/Packer/PhotonOS4/packer-photon.json.pkr.hcl matches what is set in the kickstart file above</p>



<pre class="urvanov-syntax-highlighter-plain-tag">packer build -var-file=nable.auto.pkrvars.hcl -var-file=vars iso-local-4.0GA.json -only=vsphere-iso.vmware-template packer-photon.json.pkr.hcl</pre>



<h2 class="wp-block-heading">Deploy Photon 4 VM</h2>



<p>For production systems, I typically use Terraform to deploy my VMs, and that&#8217;s what I did. I&#8217;m not going to go over that, as I&#8217;ve done it before. If nothing else, just deploy the VM from a template, assign it a static IP in the guest customization specification, and then log in using credentials set in the kickstart file.</p>



<h2 class="wp-block-heading">Configure Server</h2>



<h3 class="wp-block-heading">Install Packages</h3>



<p>Execute the commands below to install required packages, and to clone the repository</p>



<script src="https://gist.github.com/jonhowe/b66c9d6881db4ec00c30852d292f6102.js"></script>



<h3 class="wp-block-heading">Configure Shims</h3>



<p>There&#8217;s a bit of config we&#8217;ll need to do in order to make this production ready.</p>



<h4 class="wp-block-heading">Configure Teams</h4>



<p>A fellow VMware vExpert, Shane Moore has an excellent article. So that I don&#8217;t recreate the wheel, please <a rel="noreferrer noopener" href="https://www.virtuallyshane.com/posts/how-to-send-vrealize-operations-alerts-into-microsoft-teams" target="_blank">see his instructions</a> for how to prep your environment to use Microsoft Teams.</p>



<p>In short, you&#8217;ll create a webhook connector in the Microsoft Teams channel, and plug the URL that you get from Teams into the teams shim file.</p>



<h4 class="wp-block-heading">Configure OpsGenie</h4>



<p>OpsGenie is pretty simple. All we&#8217;ll need to do is create an integration by selecting your team in Opsgenie, navigating to Integrations, then selecting Add Integration.</p>



<figure class="wp-block-gallery columns-1 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex"><ul class="blocks-gallery-grid"><li class="blocks-gallery-item"><figure><a href="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-1024x138.png"><img decoding="async" width="1024" height="138" src="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-1024x138.png" alt="" data-id="1447" class="wp-image-1447" srcset="/wp-content/uploads/2021/07/image-1024x138.png 1024w, /wp-content/uploads/2021/07/image-300x40.png 300w, /wp-content/uploads/2021/07/image-768x104.png 768w, /wp-content/uploads/2021/07/image-1536x207.png 1536w, /wp-content/uploads/2021/07/image.png 1660w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure></li></ul></figure>



<p>In the resulting list of available integrations, select API.</p>



<figure class="wp-block-gallery columns-1 is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex"><ul class="blocks-gallery-grid"><li class="blocks-gallery-item"><figure><a href="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-1.png"><img decoding="async" width="229" height="189" src="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-1.png" alt="" data-id="1448" class="wp-image-1448"/></a></figure></li></ul></figure>



<p>Then note the API key (you can grab it later, it doesn&#8217;t disappear when you navigate away). We&#8217;ll use that when we configure outbound settings in vROps to use OpsGenie.</p>



<h4 class="wp-block-heading">Disable Unused Shims</h4>



<p>In my environment, I&#8217;m only going to be using Teams and OpsGenie alerts. To reduce bloat and access points that could cause me security issues, I&#8217;m disabling all shims not in use.</p>



<p>Edit the file 
			<span id="urvanov-syntax-highlighter-667f6dc94eeaa147438448" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-v">loginsightwebhookdemo</span><span class="crayon-o">/</span><span class="crayon-v">webhook</span><span class="crayon-o">-</span><span class="crayon-v">shims</span><span class="crayon-o">/</span><span class="crayon-v">loginsightwebhookdemo</span><span class="crayon-o">/</span><span class="crayon-v">__init__</span><span class="crayon-sy">.</span><span class="crayon-v">py</span></span></span></p>



<script src="https://gist.github.com/jonhowe/1d6fa1a003732c7200ec1ca28e509751.js"></script>



<h4 class="wp-block-heading">Disable Welcome Page</h4>



<p>This could probably be optional, but I appreciate not having a welcome/hello world webpage open for a production service. We&#8217;ll disable it.</p>



<p><meta http-equiv="content-type" content="text/html; charset=utf-8">Edit the file 
			<span id="urvanov-syntax-highlighter-667f6dc94eeae312607166" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-v">loginsightwebhookdemo</span><span class="crayon-o">/</span><span class="crayon-v">webhook</span><span class="crayon-o">-</span><span class="crayon-v">shims</span><span class="crayon-o">/</span><span class="crayon-v">loginsightwebhookdemo</span><span class="crayon-o">/</span><span class="crayon-v">__init__</span><span class="crayon-sy">.</span><span class="crayon-v">py</span></span></span></p>



<script src="https://gist.github.com/jonhowe/872a49c369ee36ff9bee6be431572a49.js"></script>



<h2 class="wp-block-heading">Configure Systemd</h2>



<p>Create two files: 
			<span id="urvanov-syntax-highlighter-667f6dc94eeb0015271836" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-o">/</span><span class="crayon-v">etc</span><span class="crayon-o">/</span><span class="crayon-v">systemd</span><span class="crayon-o">/</span><span class="crayon-v">system</span><span class="crayon-o">/</span><span class="crayon-v">gunicorn</span><span class="crayon-sy">.</span><span class="crayon-v">service</span></span></span> and 
			<span id="urvanov-syntax-highlighter-667f6dc94eeb2356589128" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-o">/</span><span class="crayon-v">etc</span><span class="crayon-o">/</span><span class="crayon-v">systemd</span><span class="crayon-o">/</span><span class="crayon-v">system</span><span class="crayon-o">/</span><span class="crayon-v">gunicorn</span><span class="crayon-sy">.</span><span class="crayon-v">socket</span></span></span> and populate with the text below. </p>



<p>
			<span id="urvanov-syntax-highlighter-667f6dc94eeb3283971875" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-o">/</span><span class="crayon-v">etc</span><span class="crayon-o">/</span><span class="crayon-v">systemd</span><span class="crayon-o">/</span><span class="crayon-v">system</span><span class="crayon-o">/</span><span class="crayon-v">gunicorn</span><span class="crayon-sy">.</span><span class="crayon-v">service</span></span></span></p>



<p>This service file ensures that Gunicorn is started the same way, and is managed by systemd. You&#8217;ll note that it <em>requires</em> gunicorn.socket, which we will create later.</p>



<script src="https://gist.github.com/jonhowe/e6b1d294dca6235f00b80c58a6f31af6.js"></script>



<p>
			<span id="urvanov-syntax-highlighter-667f6dc94eeb4459047386" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-o">/</span><span class="crayon-v">etc</span><span class="crayon-o">/</span><span class="crayon-v">systemd</span><span class="crayon-o">/</span><span class="crayon-v">system</span><span class="crayon-o">/</span><span class="crayon-v">gunicorn</span><span class="crayon-sy">.</span><span class="crayon-v">socket</span></span></span></p>



<p>This socket file sets permissions for the socket assigned to gunicorn</p>



<script src="https://gist.github.com/jonhowe/8398a06c4395763a82faa480de19206e.js"></script>



<h2 class="wp-block-heading">Configure Nginx</h2>



<p>Replace the file 
			<span id="urvanov-syntax-highlighter-667f6dc94eeb5744894421" class="urvanov-syntax-highlighter-syntax urvanov-syntax-highlighter-syntax-inline  crayon-theme-classic crayon-theme-classic-inline urvanov-syntax-highlighter-font-monaco" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important;"><span class="crayon-pre urvanov-syntax-highlighter-code" style="font-size: 12px !important; line-height: 15px !important;font-size: 12px !important; -moz-tab-size:4; -o-tab-size:4; -webkit-tab-size:4; tab-size:4;"><span class="crayon-o">/</span><span class="crayon-v">etc</span><span class="crayon-o">/</span><span class="crayon-v">nginx</span><span class="crayon-o">/</span><span class="crayon-v">nginx</span><span class="crayon-sy">.</span><span class="crayon-v">conf</span></span></span> with the contents below</p>



<p>This is telling Nginx to connect directly to the socket we&#8217;re creating with the systemd socket gunicorn.socket we created earlier.</p>



<script src="https://gist.github.com/jonhowe/78964d1cc4a32bf5e13a7369a36eaa13.js"></script>



<h2 class="wp-block-heading">Enable and Start All Services</h2>



<p>Finally, enable, and start both services, and restart Nginx</p>



<div class="wp-block-urvanov-syntax-highlighter-code-block"><pre class="urvanov-syntax-highlighter-plain-tag">systemctl enable gunicorn.socket
systemctl enable gunicorn.service
systemctl restart gunicorn.socket 
systemctl restart gunicorn.service
systemctl restart nginx.service</pre></div>



<h2 class="wp-block-heading">Configure vRealize Operations Manager</h2>



<p>At this point, all we need to do is configure an outbound instance for Microsoft Teams and OpsGenie. </p>



<h3 class="wp-block-heading">Add a New Rest Notification Plugin</h3>



<h4 class="wp-block-heading">OpsGenie</h4>



<p>To do this, sign into vROps, and navigate to Administration -&gt;Management-&gt;Outbound Settings, or https://[Your_vROps_URL]/ui/index.action#/administration/outbound-alert-settings</p>



<figure class="wp-block-gallery columns-1 is-cropped wp-block-gallery-3 is-layout-flex wp-block-gallery-is-layout-flex"><ul class="blocks-gallery-grid"><li class="blocks-gallery-item"><figure><a href="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-2.png"><img loading="lazy" decoding="async" width="636" height="351" src="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-2.png" alt="" data-id="1452" class="wp-image-1452" srcset="/wp-content/uploads/2021/07/image-2.png 636w, /wp-content/uploads/2021/07/image-2-300x166.png 300w" sizes="(max-width: 636px) 100vw, 636px" /></a></figure></li></ul></figure>



<p>After you select the Rest Notification Plugin, there are 3 fields required in the Add/Edit Outbound Instance box</p>



<figure class="wp-block-table"><table><tbody><tr><td>Item</td><td>Description</td><td>Example</td></tr><tr><td>Instance Name</td><td>Name of the rest notification plugin created</td><td>Opsgenie</td></tr><tr><td>URL</td><td>URL to OpsGenie shim endpoint</td><td>http://&lt;IP/ or Hostname of Photon VM&gt;/endpoint/opsgenie/&lt;api key&gt;</td></tr><tr><td>Content Type</td><td>Content Type &#8211; Unless you&#8217;re working with a SOAP API (which we aren&#8217;t), this will always be application/json</td><td></td></tr></tbody></table></figure>



<figure class="wp-block-gallery columns-1 is-cropped wp-block-gallery-4 is-layout-flex wp-block-gallery-is-layout-flex"><ul class="blocks-gallery-grid"><li class="blocks-gallery-item"><figure><a href="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-3.png"><img loading="lazy" decoding="async" width="580" height="479" src="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-3.png" alt="" data-id="1453" class="wp-image-1453" srcset="/wp-content/uploads/2021/07/image-3.png 580w, /wp-content/uploads/2021/07/image-3-300x248.png 300w" sizes="(max-width: 580px) 100vw, 580px" /></a></figure></li></ul></figure>



<p>Finally, navigate to Alerts -&gt; Configuration -&gt; Notification (https://<meta http-equiv="content-type" content="text/html; charset=utf-8">[Your_vROps_URL]/ui/index.action#/alerts/notifications) and add a new rule that targets the adapter you just created.</p>



<figure class="wp-block-gallery columns-1 is-cropped wp-block-gallery-5 is-layout-flex wp-block-gallery-is-layout-flex"><ul class="blocks-gallery-grid"><li class="blocks-gallery-item"><figure><a href="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-4.png"><img loading="lazy" decoding="async" width="883" height="486" src="https://www.virtjunkie.com/wp-content/uploads/2021/07/image-4.png" alt="" data-id="1454" class="wp-image-1454" srcset="/wp-content/uploads/2021/07/image-4.png 883w, /wp-content/uploads/2021/07/image-4-300x165.png 300w, /wp-content/uploads/2021/07/image-4-768x423.png 768w" sizes="(max-width: 883px) 100vw, 883px" /></a></figure></li></ul></figure>



<h4 class="wp-block-heading">Teams</h4>



<p>Again, I&#8217;m not in the business of recreating the wheel, <a href="https://www.virtuallyshane.com/posts/how-to-send-vrealize-operations-alerts-into-microsoft-teams" target="_blank" rel="noreferrer noopener">so check out Shane&#8217;s blog for info on how to do this</a>.</p>



<h2 class="wp-block-heading">References</h2>



<figure class="wp-block-table"><table><tbody><tr><td><a href="https://www.virtuallyshane.com/posts/how-to-send-vrealize-operations-alerts-into-microsoft-teams" target="_blank" rel="noreferrer noopener">https://www.virtuallyshane.com/posts/how-to-send-vrealize-operations-alerts-into-microsoft-teams</a></td><td>Fellow vExpert Shane Moore&#8217;s article for setting MS Teams forwarding</td></tr><tr><td><a href="https://github.com/vmw-loginsight/webhook-shims" target="_blank" rel="noreferrer noopener">https://github.com/vmw-loginsight/webhook-shims</a></td><td>Official Github site for the webhook-shims project</td></tr><tr><td><a href="https://blogs.vmware.com/management/2017/01/vrealize-webhooks-infinite-integrations.html" target="_blank" rel="noreferrer noopener">https://blogs.vmware.com/management/2017/01/vrealize-webhooks-infinite-integrations.html</a></td><td>VMware Blog article that got me started on this journey</td></tr><tr><td><a href="https://vmware.github.io/photon/docs/user-guide/working-with-kickstart/" target="_blank" rel="noreferrer noopener">https://vmware.github.io/photon/docs/user-guide/working-with-kickstart/</a></td><td>VMware Photon documentation</td></tr><tr><td><a href="https://github.com/vmware/photon/issues/1113" target="_blank" rel="noreferrer noopener">https://github.com/vmware/photon/issues/1113</a></td><td>Github Issue for presenting Kickstart file to Photon over cdrom/floppy</td></tr><tr><td><a href="https://github.com/vmware/photon/issues/798" target="_blank" rel="noreferrer noopener">https://github.com/vmware/photon/issues/798</a></td><td><meta http-equiv="content-type" content="text/html; charset=utf-8">Another Github Issue for presenting Kickstart file to Photon over cdrom/floppy</td></tr></tbody></table></figure>
<p>The post <a href="/2021/07/23/vrops-opsgenie-production-setup/">Configure vROps To Send Alerts to OpsGenie and Microsoft Teams</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2021/07/23/vrops-opsgenie-production-setup/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>VMware Provisioning using Hashicorp Terraform  &#8211; Part 2</title>
		<link>/2020/07/06/vmware-provisioning-using-hashicorp-terraform-part-2/</link>
					<comments>/2020/07/06/vmware-provisioning-using-hashicorp-terraform-part-2/#respond</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Mon, 06 Jul 2020 13:00:00 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Hashicorp]]></category>
		<category><![CDATA[InfrastructureAsCode]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=1334</guid>

					<description><![CDATA[<p>In the first part of this series we went over Terraform at a very high level and discussed a basic example of using it to provision a single Windows VM or a single Linux VM. While this is a helpful baseline, it doesn&#8217;t realistically help us when defining our application structure in code. For example, [&#8230;]</p>
<p>The post <a href="/2020/07/06/vmware-provisioning-using-hashicorp-terraform-part-2/">VMware Provisioning using Hashicorp Terraform  &#8211; Part 2</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In the <a href="https://www.virtjunkie.com/vmware-provisioning-using-hashicorp-terraform/" target="_blank" rel="noreferrer noopener">first part of this series</a> we went over Terraform at a very high level and discussed a basic example of using it to provision a single Windows VM or a single Linux VM. While this is a helpful baseline, it doesn&#8217;t realistically help us when defining our application structure in code. For example, if you wanted to set up a <a rel="noreferrer noopener" href="https://en.wikipedia.org/wiki/Multitier_architecture#Three-tier_architecture" target="_blank">three tier application</a> you&#8217;ll need to have three separate instances of the project we used. At that point we&#8217;re not really gaining much efficiency over deploying a template in vCenter. In this post I&#8217;ll discuss Terraform Modules, give an example of how to store your Terraform Module in GitHub, and provide a real-life example of how to deploy a three tier application using multiple source images.</p>



<span id="more-1334"></span>



<h2 class="wp-block-heading">Introduction to Terraform Modules</h2>



<p>In Part 1 of this series I <a href="https://www.virtjunkie.com/vmware-provisioning-using-hashicorp-terraform/#main_tf" target="_blank" rel="noreferrer noopener">compared traditional programming languages to Terraform</a>. We can do the same thing with Modules. For example, with Powershell or Python, you can download a module that provides functionality and consume that functionality in your code without having to author it. The same thing happens in Terraform, and just like with other languages, you can create your own, or download one from a third party.</p>



<h3 class="wp-block-heading">Terraform Registry</h3>



<p>Thankfully, <a rel="noreferrer noopener" href="https://registry.terraform.io/" target="_blank">Hashicorp provides us with a registry</a> that we can use to find and consume Terraform Modules. At the time this post is published, the Terraform Registry contains support for <a rel="noreferrer noopener" href="https://registry.terraform.io/browse/providers" target="_blank">63 providers</a> and has <a rel="noreferrer noopener" href="https://registry.terraform.io/browse/modules" target="_blank">3454 Modules</a>. So if you are looking for specific functionality, check there first!</p>



<h2 class="wp-block-heading">Roll Your Own Module</h2>



<p>That said, you may have a need to create your own module, or if you&#8217;re like me, want to make sure you understand how modules work before you use one that someone else created.</p>



<h3 class="wp-block-heading">Best Practices</h3>



<p>First and foremost, you&#8217;ll want to take a look at the official documentation from Hashicorp on the standard module structure. It gets pretty in-depth, but I&#8217;ll hit on a few high level important items.</p>



<ul><li>Store your module in github</li><li>At the very least, make sure you split your variables and outputs into different TF files</li><li>Include an examples directory and show every variation of how to call your module. For example, if you can create a linux image or a windows image, but you need to call them differently, show an example for each.</li><li>Include a README.md file that has a description of the module, but also references your examples</li></ul>



<h3 class="wp-block-heading">Why store your module in GitHub?</h3>



<p>Aside from the wide ranging benefits of using version control, using GitHub will allow you to call a specific version of your module.</p>



<h3 class="wp-block-heading">File Structure</h3>



<p>The following files should be in your GitHub reposity. When you run <code>terraform init</code>, it will be downloaded to the .terraform directory on the machine running the project.</p>



<h4 class="wp-block-heading">main.tf</h4>



<script src="https://gist.github.com/jonhowe/7526c2316eda915116ae63248154b4cb.js"></script>



<h4 class="wp-block-heading">variables.tf</h4>



<script src="https://gist.github.com/jonhowe/5d44ecc0680f4c64447f9e7bab7b5150.js"></script>



<h4 class="wp-block-heading">output.tf</h4>



<script src="https://gist.github.com/jonhowe/81b6205c683c0a9273e29b9c62ee8a79.js"></script>



<h2 class="wp-block-heading">How to use this module?</h2>



<p>Now that we&#8217;ve created our module and have it in Github, all we need to do in order to complete our initial goal of having a three tier application is to create a single main.tf file, and call the module 3 times. Below is an example that allows us to set separate information for each of the new VMs.</p>



<script src="https://gist.github.com/jonhowe/f81432f089cb3bbc36113ce29e4f1db4.js"></script>



<h2 class="wp-block-heading">References and what&#8217;s next?</h2>



<h3 class="wp-block-heading">What&#8217;s Next?</h3>



<p>At this point we have shown how to create and <a href="https://www.virtjunkie.com/vmware-template-packer/" target="_blank" rel="noreferrer noopener">manage images using packer</a>, a <a href="https://www.virtjunkie.com/vmware-provisioning-using-hashicorp-terraform/" target="_blank" rel="noreferrer noopener">couple</a> of <a href="https://www.virtjunkie.com/vmware-provisioning-using-hashicorp-terraform-part-2/" target="_blank" rel="noreferrer noopener">parts</a> on how to use Terraform to deploy infrastructure, so all we have left is doing configuration of our newly created VMs.</p>



<ul><li>Use Ansible to configure our newly provisioned VMs</li><li>Wrap the Terraform VM Deployment process, as well as the Ansible VM configuration process together into a single process you execute once</li><li>Use Ansible to do a greenfield deployment of a vSphere environment</li></ul>



<h3 class="wp-block-heading">References</h3>



<ul><li><a rel="noreferrer noopener" href="https://www.virtjunkie.com/vmware-provisioning-using-hashicorp-terraform/" target="_blank">Part 1 &#8211; Provision VMware VMs using Terraform</a></li><li><a href="https://registry.terraform.io/">Terraform Registry</a></li><li><a rel="noreferrer noopener" href="https://www.terraform.io/docs/modules/index.html#standard-module-structure" target="_blank">Module Structure</a></li></ul>
<p>The post <a href="/2020/07/06/vmware-provisioning-using-hashicorp-terraform-part-2/">VMware Provisioning using Hashicorp Terraform  &#8211; Part 2</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2020/07/06/vmware-provisioning-using-hashicorp-terraform-part-2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Jitsi for Just in Time Conferencing using Terraform on Vultr with Route 53</title>
		<link>/2020/05/04/jitsi-jit-conferencing-tf-vultr-route53/</link>
					<comments>/2020/05/04/jitsi-jit-conferencing-tf-vultr-route53/#respond</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Mon, 04 May 2020 13:00:00 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[BASH]]></category>
		<category><![CDATA[Hashicorp]]></category>
		<category><![CDATA[InfrastructureAsCode]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Servers]]></category>
		<category><![CDATA[Terraform]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=1304</guid>

					<description><![CDATA[<p>With everything going on in the world with COVID-19 and the social distancing that is happening, people are looking to connect with friends, family and co-workers via Video conferencing more than ever. Recent vulnerabilities in Zoom have made people more cognizant than ever that security needs to be considered when using these platforms no matter [&#8230;]</p>
<p>The post <a href="/2020/05/04/jitsi-jit-conferencing-tf-vultr-route53/">Jitsi for Just in Time Conferencing using Terraform on Vultr with Route 53</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>With everything going on in the world with COVID-19 and the social distancing that is happening, people are looking to connect with friends, family and co-workers via Video conferencing more than ever. Recent vulnerabilities in Zoom have made people more cognizant than ever that security needs to be considered when using these platforms no matter what you are using them for.</p>



<p><a href="https://jitsi.org/" target="_blank" rel="noreferrer noopener">Jitsi is an open source video conferencing platform</a> that I&#8217;ve been hearing about a lot lately, and finally had a chance to look into. In this post I&#8217;ll explain how to use Terraform to provision a Jitsi instance when you need a conference and tear it down when you are done. We&#8217;ll be using Vultr and their Jitsi &#8220;application&#8221; and AWS Route 53 for DNS.</p>



<span id="more-1304"></span>



<h2 class="wp-block-heading">Why Am I Writing This Article, and What Does It Accomplish?</h2>



<p>Why am I writing this article?</p>



<ol><li>We <strong>always</strong> want to have our apps and infrastructure defined in code</li><li>We pay for traditional web conferencing software 24 hours a day, 7 days a week, regardless of if we are are using running a conference or not. Why don&#8217;t we spin up conference infrastructure <strong>when we need it, and tear it down when we don&#8217;t</strong>?</li></ol>



<p>At a high level, this project will accomplish the following:</p>



<ol><li>Provision a Vultr VPS that is pre-configured with Jitsi</li><li>Take the IP Address that Vultr assigns the VPS and use it to create an A Record in Route 53</li><li>Copy a script to your VPS that will be used to finish the Jitsi configuration</li><li>Run the script that we copied and pass a few command line arguments that are specific to our environment</li></ol>



<h2 class="wp-block-heading">Prerequisites</h2>



<p>In addition to having Terraform downloaded and installed, we&#8217;ll need the following items:</p>



<h3 class="wp-block-heading">Vultr Account + API Access</h3>



<p>Vultr is definitely my go-to for VPS&#8217;s these days. Not only because of their price/performance/feature availability ratio, but because they provide a number of pre-configured applications that are ready, or near ready for use. <a rel="noreferrer noopener" href="https://www.vultr.com/docs/one-click-jitsi" target="_blank">Jitsi is one of these applications</a>. If you do use Vultr, please do me a favor and use&nbsp;<a rel="noreferrer noopener" href="https://www.vultr.com/?ref=8531966-6G" target="_blank">this link</a>&nbsp;to sign up. I’ll get a little kickback, but you’ll get $100 USD to use on the site in your first month.</p>



<div class="wp-block-media-text alignwide has-media-on-the-right is-stacked-on-mobile"><figure class="wp-block-media-text__media"><img loading="lazy" decoding="async" width="1024" height="450" src="https://www.virtjunkie.com/wp-content/uploads/2020/05/2020-05-02_19-45-1024x450.png" alt="" class="wp-image-1305" srcset="/wp-content/uploads/2020/05/2020-05-02_19-45-1024x450.png 1024w, /wp-content/uploads/2020/05/2020-05-02_19-45-300x132.png 300w, /wp-content/uploads/2020/05/2020-05-02_19-45-768x338.png 768w, /wp-content/uploads/2020/05/2020-05-02_19-45.png 1273w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure><div class="wp-block-media-text__content">
<p class="has-normal-font-size">Once you have a Vultr account, you&#8217;ll need to generate and record an API key to use with Terraform. Use the steps below to generate it.</p>



<ol><li>Log into Vultr</li><li>Navigate to Settings, and then API</li><li>Generate an API key, and copy it somewhere safe, we&#8217;ll be using it later</li></ol>
</div></div>



<h3 class="wp-block-heading">AWS Account + API Access</h3>



<p>We&#8217;ll be using <a rel="noreferrer noopener" href="https://aws.amazon.com/route53/" target="_blank">AWS&#8217;s Route 53 service</a>, which is really just a fancy DNS service that&#8217;s hooked into AWS.  In order to automate Route 53 with Terraform, we&#8217;ll need to enable API access.</p>



<div class="wp-block-media-text alignwide has-media-on-the-right is-stacked-on-mobile" style="grid-template-columns:auto 70%"><figure class="wp-block-media-text__media"><img loading="lazy" decoding="async" width="1024" height="400" src="https://www.virtjunkie.com/wp-content/uploads/2020/05/2020-05-02_20-13-1024x400.png" alt="" class="wp-image-1307" srcset="/wp-content/uploads/2020/05/2020-05-02_20-13-1024x400.png 1024w, /wp-content/uploads/2020/05/2020-05-02_20-13-300x117.png 300w, /wp-content/uploads/2020/05/2020-05-02_20-13-768x300.png 768w, /wp-content/uploads/2020/05/2020-05-02_20-13-1536x599.png 1536w, /wp-content/uploads/2020/05/2020-05-02_20-13-1568x612.png 1568w, /wp-content/uploads/2020/05/2020-05-02_20-13.png 1607w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure><div class="wp-block-media-text__content">
<p><a rel="noreferrer noopener" href="https://console.aws.amazon.com/iam/home?#security_credential" target="_blank">Use this link to access the IAM Management page</a></p>



<ol><li>Expand the &#8220;Access Keys&#8221; blade</li><li>Select &#8220;Create New Access Key</li><li>Save the resulting file, as we&#8217;ll use the contents later</li></ol>
</div></div>



<h3 class="wp-block-heading">Domain Registrar Using Custom Nameservers</h3>



<p>In addition to the above, the domain you want to use will need to be configured to use the Route 53 Name Servers. Route 53 will provide you the nameservers when you create a zone, and you&#8217;ll simply plug those into your registrar DNS settings page. I&#8217;m not going to explain how to create a zone in Route 53, or how to configure your registrar, but if you have questions, throw them in the comments and I&#8217;ll do my best to help.</p>



<h2 class="wp-block-heading">Getting Started</h2>



<h3 class="wp-block-heading">Run This Project</h3>



<ol><li>Grab the files below, or copy them from my <a rel="noreferrer noopener" href="https://github.com/jonhowe/Virtjunkie.com/tree/master/Jitsi-JIT-Conferencing-TF-Vultr-Route53" target="_blank">Github Repository</a></li><li>Enter the directory that contains the files</li><li>At a minimum, modify the fields in the auto.tfvars file<ol><li>vultr_api_key</li></ol><ol><li>aws_access_key</li><li>aws_secret_key</li><li>domain</li><li>email</li></ol></li><li>Initialize Terraform by running <strong><code>terraform init</code></strong></li><li>Create a terraform plan by running <strong><code>terraform plan</code></strong></li><li>Apply the configuration by running <strong><code>terraform apply</code></strong></li><li>Voila! In less than 5 minutes, you&#8217;ve got a functional, secure Jitsi instance, running on a server and domain you control. Upon successful creation, you&#8217;ll see text like what we see below giving you the URL and credentials. When you are done with your conference, just run <code><strong>terraform destroy</strong></code> to stop from receiving charges on a server/service you aren&#8217;t using.</li></ol>



<pre class="urvanov-syntax-highlighter-plain-tag">null_resource.jitsi_config (remote-exec): ------------------------------
null_resource.jitsi_config (remote-exec): |                            |
null_resource.jitsi_config (remote-exec): |   JITSI SETUP COMPLETED!   |
null_resource.jitsi_config (remote-exec): |                            |
null_resource.jitsi_config (remote-exec): ------------------------------
null_resource.jitsi_config (remote-exec): JITSI URL: https://conference.yourdomain.com/

null_resource.jitsi_config (remote-exec): USERNAME: admin
null_resource.jitsi_config (remote-exec): PASSWORD: @#$asdfahgsd34579--23%4asdf</pre>



<h2 class="wp-block-heading">Code</h2>



<h3 class="wp-block-heading">Main.tf</h3>



<p>This file does all of the work.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">#main.tf
#https://www.virtjunkie.com/jitsi-jit-conferencing-tf-vultr-route53/
#https://github.com/jonhowe/Virtjunkie.com/tree/master/Jitsi-JIT-Conferencing-TF-Vultr-Route53

#Conifugre the Vultr provider
provider &quot;vultr&quot; {
  api_key = var.vultr_api_key
  rate_limit = 700
  retry_limit = 3
}

#Configure the AWS Provider
provider &quot;aws&quot; {
  #profile    = &quot;default&quot;
  #shared_credentials_file = &quot;/home/jhowe/storage/btsync/folders/Sync/awscredentials/credentials&quot;
  region     = var.aws_region
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
}

#https://www.terraform.io/docs/providers/aws/d/route53_zone.html
data &quot;aws_route53_zone&quot; &quot;selected&quot; {
  name         = &quot;${var.domain}.&quot;
  private_zone = false
}

#Provision Vultr Server
resource &quot;vultr_server&quot; &quot;my_server&quot; {
    plan_id = var.vultr_plan_id
    region_id = var.vultr_region
    app_id = var.vultr_app_id
    label = &quot;${var.hostname}.${var.domain}&quot;
    tag = var.vultr_tag
    hostname = &quot;${var.hostname}.${var.domain}&quot;
    enable_ipv6 = false
    auto_backup = false
    ddos_protection = false
    notify_activate = false

    connection {
        type     = &quot;ssh&quot;
        user     = &quot;root&quot;
        
        #https://www.terraform.io/docs/providers/vultr/r/server.html#default_password
        password = self.default_password

        #https://www.terraform.io/docs/provisioners/connection.html#the-self-object
        host     = self.main_ip
    }

    provisioner &quot;local-exec&quot; {
      command = &quot;echo SSH to this server with the command: ssh root@${vultr_server.my_server.main_ip} with the password '${vultr_server.my_server.default_password}'&quot;
    }
}

#Create the Route 53 A Record
#https://www.terraform.io/docs/providers/aws/r/route53_record.html
resource &quot;aws_route53_record&quot; &quot;conference&quot; {
  zone_id = data.aws_route53_zone.selected.zone_id
  name    = &quot;${var.hostname}.${data.aws_route53_zone.selected.name}&quot;
  type    = &quot;A&quot;
  ttl     = &quot;300&quot;
  records = &amp;#91;&quot;${vultr_server.my_server.main_ip}&quot;]
}

#This null resource exists to handle configuration of the Vultr VPS after Route 53
resource &quot;null_resource&quot; &quot;jitsi_config&quot; {
    
    connection {
        type     = &quot;ssh&quot;
        user     = &quot;root&quot;
        
        #https://www.terraform.io/docs/providers/vultr/r/server.html#default_password
        password = vultr_server.my_server.default_password

        #https://www.terraform.io/docs/provisioners/connection.html#the-self-object
        host     = vultr_server.my_server.main_ip
    }

    provisioner &quot;file&quot; {
        source      = &quot;./configure_jitsi_param.sh&quot;
        destination = &quot;/root/configure_jitsi_param.sh&quot;
    }

    provisioner &quot;remote-exec&quot; {
        inline = &amp;#91;
            &quot;chmod +x /root/configure_jitsi_param.sh&quot;,
            &quot;/root/configure_jitsi_param.sh ${var.hostname}.${var.domain} ${var.email} y&quot;
        ]
    }
}</pre>



<h3 class="wp-block-heading">Variables.tf</h3>



<p>This file defines the variables that we will use in main.tf</p>



<pre class="urvanov-syntax-highlighter-plain-tag">#variables.tf
#https://www.virtjunkie.com/jitsi-jit-conferencing-tf-vultr-route53/
#https://github.com/jonhowe/Virtjunkie.com/tree/master/Jitsi-JIT-Conferencing-TF-Vultr-Route53

variable &quot;vultr_api_key&quot; {
    description = &quot;API Key Used by Vultr (https://my.vultr.com/settings/#settingsapi)&quot;
}

variable &quot;vultr_region&quot; {
    description = &quot;Vultr Region Selection (curl https://api.vultr.com/v1/regions/availability?DCID=1)&quot;
    default = 1
}

variable &quot;vultr_plan_id&quot; {
    description = &quot;Vultr Plan for the VPS to use (curl https://api.vultr.com/v1/plans/list)&quot;
    default = 202
}

variable &quot;vultr_tag&quot; {
    description = &quot;Vultr Tag to apply to the new VPS&quot;
    default = &quot;jitsi-conference&quot;
}

variable &quot;vultr_app_id&quot; {
    description = &quot;Vultr App to pre-install. This should always be '47', if jitsi is being provisioned (curl https://api.vultr.com/v1/app/list)&quot;
    default = 47
}

variable &quot;hostname&quot; {
    description = &quot;Hostname to be used&quot;
    default = &quot;conferences&quot;
}

variable &quot;email&quot; {
    description = &quot;email to be used for let's encrypt acme config&quot;
    default = &quot;john.doe@email.com&quot;
}

variable &quot;domain&quot; {
    description = &quot;domain to be used&quot;
    default = &quot;aremyj.am&quot;
}

variable &quot;aws_access_key&quot; {
    description = &quot;AWS Access Key - get it here: (https://console.aws.amazon.com/iam/home?#security_credential)&quot;
}

variable &quot;aws_secret_key&quot; {
    description = &quot;AWS Secret Key - get it here: (https://console.aws.amazon.com/iam/home?#security_credential)&quot;
}

variable &quot;aws_region&quot; {
    description = &quot;AWS Region&quot;
    default = &quot;us-east-1&quot;
}</pre>



<h3 class="wp-block-heading">[yourdomain].auto.tfvars</h3>



<p>The auto.tfvars file provides values to the variables defined in the variables.tf file. You&#8217;ll have to create this file from scratch, and terraform best practices dictate that you exclude this file from source control. Here&#8217;s an example you can use. Modify this for your environment. The name doesn&#8217;t matter, as long as it ends with auto.tfvars.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">vultr_api_key = &quot;&amp;#91;fill this in]&quot;
vultr_region = 1
vultr_plan_id = 202
vultr_app_id = 47
vultr_tag = &quot;jitsi-conference&quot;
hostname = &quot;conference&quot;
email = &quot;your.email@address.org&quot;
domain = &quot;your-domain.com&quot;
aws_region = &quot;us-east-1&quot;
aws_access_key = &quot;&amp;#91;fill this in]&quot;
aws_secret_key = &quot;&amp;#91;fill this in]&quot;</pre>



<h3 class="wp-block-heading">configure_jitsi_param.sh</h3>



<p>Full disclosure, I did not create this script. Vultr created it, and provides it on your Jitsi VPS when you request it. Unfortunately, the version they provide is intended to be executed interactively, so I made a few very minor modifications to allow for us to run it with parameters.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">#!/bin/bash
#This script was copied from /opt/vultr/configure_jitsi.sh on a Vultr VPS that has the one-click Jitsi App
#I added lines 7-9 to allow for adding parameters on the CLI and commented lines 11-13 to force the variables to be provided on the CLI
#https://www.vultr.com/docs/one-click-jitsi
#https://www.virtjunkie.com/jitsi-jit-conferencing-tf-vultr-route53/
#https://github.com/jonhowe/Virtjunkie.com/tree/master/Jitsi-JIT-Conferencing-TF-Vultr-Route53
HOSTNAME=$1
EMAIL=$2
response=$3
# User choices
#read -ep &quot;Please specify which domain you would like to use: &quot; HOSTNAME
#read -ep &quot;Please enter your email address for Let's Encrypt Registration: &quot; EMAIL
#read -r -p &quot;Would you like to enable password authorization? &amp;#91;y/N] &quot; response
case &quot;$response&quot; in
    &amp;#91;yY]&amp;#91;eE]&amp;#91;sS]|&amp;#91;yY])
        AUTH=1
        ;;
    *)
        AUTH=0
        ;;
esac


PROSODYPATH=/etc/prosody/conf.avail/${HOSTNAME}.cfg.lua
JITSIPATH=/etc/jitsi/meet/${HOSTNAME}-config.js
JICOFOPATH=/etc/jitsi/jicofo/sip-communicator.properties

# Remove and purge (Stop first and wait to avoid race condition)
purgeold() {        
        /opt/vultr/stopjitsi.sh
        sleep 5
        apt -y purge jigasi jitsi-meet jitsi-meet-web-config jitsi-meet-prosody jitsi-meet-turnserver jitsi-meet-web jicofo jitsi-videobridge2 jitsi*
}

# Reinstall
reinstalljitsi() {
        echo &quot;jitsi-videobridge2 jitsi-videobridge/jvb-hostname string ${HOSTNAME}&quot; | debconf-set-selections
        echo &quot;jitsi-meet-web-config jitsi-meet/cert-choice string Generate a new self-signed certificate (You will later get a chance to obtain a Let's encrypt certificate)&quot; | debconf-set-selections
        apt-get -y install jitsi-meet
}

# Remove nginx defaults
wipenginx() {
        rm -f /etc/nginx/sites-enabled/default
}

# Configure Lets Encrypt
configssl(){
    systemctl restart nginx
    sed -i -e 's/echo.*Enter your email and press.*/EMAIL=$1/' /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh
    sed -i -e 's/read EMAIL//'  /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh
    /usr/share/jitsi-meet/scripts/install-letsencrypt-cert.sh ${EMAIL}
}

configprosody() {
  AUHTLINE='authentication = &quot;internal_plain&quot;'
  sed -i &quot;s/authentication\ \=\ \&quot;anonymous\&quot;/${AUTHLINE}/g&quot; ${PROSODYPATH}
  cat &amp;lt;&amp;lt; EOT &gt;&gt; ${PROSODYPATH}

VirtualHost &quot;guest.${HOSTNAME}&quot;
    authentication = &quot;anonymous&quot;
    c2s_require_encryption = false

EOT
}

configjitsi() {
        sed -i &quot;s/\/\/\ anonymousdomain\:\ 'guest.example.com',/anonymousdomain\:\ 'guest.${HOSTNAME}',/g&quot; ${JITSIPATH}
}

configjicofo() {
        echo &quot;org.jitsi.jicofo.auth.URL=XMPP:${HOSTNAME}&quot; &gt;&gt; ${JICOFOPATH}
}

registeruser(){
        PASSWORD=$(&amp;lt; /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-16};echo;)
        prosodyctl register admin ${HOSTNAME} ${PASSWORD}
}

restartjitsi() {
        /opt/vultr/stopjitsi.sh
        /opt/vultr/startjitsi.sh
}

completedsetup(){
    echo &quot;&quot;
    echo &quot;------------------------------&quot;
    echo &quot;|                            |&quot;
    echo &quot;|   JITSI SETUP COMPLETED!   |&quot;
    echo &quot;|                            |&quot;
    echo &quot;------------------------------&quot;
    echo &quot;JITSI URL: https://${HOSTNAME}&quot;/
    echo &quot;&quot;
}

outputUser(){
    echo &quot;USERNAME: admin&quot;
    echo &quot;PASSWORD: ${PASSWORD}&quot;
    echo &quot;&quot;
}

# Script start

purgeold
reinstalljitsi
wipenginx
configssl
if &amp;#91; &quot;$AUTH&quot; == &quot;1&quot; ]; then
    configprosody
    configjitsi
    configjicofo
    registeruser
    restartjitsi    
fi
completedsetup
if &amp;#91; &quot;$AUTH&quot; == &quot;1&quot; ]; then
    outputUser
fi</pre>



<h2 class="wp-block-heading">Summary + More Reading</h2>



<p>There you have it! With this project you can have a fully functional Jitsi instance on your own domain with end to end encryption in less than 5 minutes. When you are done, there&#8217;s no harm in deleting it so you aren&#8217;t charged.</p>



<p>Here are some references I used while creating this:</p>



<ul><li><a href="https://github.com/jonhowe/Virtjunkie.com/tree/master/Jitsi-JIT-Conferencing-TF-Vultr-Route53">https://github.com/jonhowe/Virtjunkie.com/tree/master/Jitsi-JIT-Conferencing-TF-Vultr-Route53</a></li><li><a href="https://www.vultr.com/docs/one-click-jitsi">https://www.vultr.com/docs/one-click-jitsi</a></li><li><a href="https://www.terraform.io/docs/providers/aws/d/route53_zone.html">https://www.terraform.io/docs/providers/aws/d/route53_zone.html</a></li><li><a href="https://www.terraform.io/docs/providers/aws/r/route53_record.html">https://www.terraform.io/docs/providers/aws/r/route53_record.html</a></li><li><a href="https://www.terraform.io/docs/providers/vultr/r/server.html#default_password">https://www.terraform.io/docs/providers/vultr/r/server.html#default_password</a></li><li><a href="https://www.terraform.io/docs/provisioners/connection.html#the-self-object">https://www.terraform.io/docs/provisioners/connection.html#the-self-object</a></li><li>Create Vultr API Key: <a href="https://my.vultr.com/settings/#settingsapi">https://my.vultr.com/settings/#settingsapi</a></li><li>Create AWS Access/Secret Key: <a href="https://console.aws.amazon.com/iam/home?#security_credential">https://console.aws.amazon.com/iam/home?#security_credential</a></li><li>Vultr API Reference &#8211; has examples that will get you plan, region, and app IDs. <a href="https://www.vultr.com/api/">https://www.vultr.com/api/</a></li></ul>
<p>The post <a href="/2020/05/04/jitsi-jit-conferencing-tf-vultr-route53/">Jitsi for Just in Time Conferencing using Terraform on Vultr with Route 53</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2020/05/04/jitsi-jit-conferencing-tf-vultr-route53/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VMware Provisioning using Hashicorp Terraform</title>
		<link>/2020/04/22/vmware-provisioning-using-hashicorp-terraform/</link>
					<comments>/2020/04/22/vmware-provisioning-using-hashicorp-terraform/#comments</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Wed, 22 Apr 2020 13:00:00 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Hashicorp]]></category>
		<category><![CDATA[Terraform]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=1181</guid>

					<description><![CDATA[<p>As a part of my effort to use Infrastructure as Code to define and automate VMware environments, I'm taking a look at Terraform for VMware provisioning. In this article, I will give a brief intro to Terraform, talk about how it can help in managing your enterprise environments, as well as how it's different than Ansible. I'll also provide example code and description for how to provision Windows and Linux VMs. </p>
<p>The post <a href="/2020/04/22/vmware-provisioning-using-hashicorp-terraform/">VMware Provisioning using Hashicorp Terraform</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>As a part of my effort to use Infrastructure as Code to define and automate VMware environments, I&#8217;m taking a look at Terraform for VMware provisioning. In this article, I will give a brief intro to Terraform, talk about how it can help in managing your enterprise environments, as well as how it&#8217;s different than Ansible. I&#8217;ll also provide example code and description for how to provision Windows and Linux VMs. </p>



<span id="more-1181"></span>



<h2 class="wp-block-heading">Source Code</h2>



<p>As always, you can find all of the source code for this project on my <a href="https://github.com/jonhowe/Virtjunkie.com/tree/master/Terraform" target="_blank" rel="noreferrer noopener">Github account</a>.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Terraform Intro</h2>



<p>According to Hashicorp, <em>&#8220;Terraform is a tool for building, changing, and versioning infrastructure safely and efficiently. Terraform can manage existing and popular service providers as well as custom in-house solutions&#8221;</em>. </p>
</div></div>



<p>Like in <a rel="noreferrer noopener" href="https://www.virtjunkie.com/vmware-template-packer/" target="_blank">my packer article</a>, I want to be clear that this isn&#8217;t a Terraform 101 article. Hashicorp provides some fairly good documentation, and the internet is full of articles explaining how to get going with Terraform.  That said, I will provide a short references for some of the building blocks of Terraform.</p>
</div></div>
</div></div>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Terraform VS. Deploying VMware Templates in vCenter VS. Ansible</h2>



<p>Should you use Terraform to provision VMs instead of deploying a VM from vCenter? Should you use Ansible instead of either of them? As with everything in technology these days, it depends. The skill we should all work towards is developing the ability to determine what tool we should use for the task at hand.</p>
</div></div>



<h3 class="wp-block-heading">Deploying VMware Templates in vCenter</h3>



<p>Nothing new here.. log into vCenter, deploy a VM from a template, use a guest customization specification. The pro&#8217;s are obvious, so I&#8217;ll skip over them and focus on the cons.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<p><strong>Cons:</strong></p>



<ul><li>Multi-step manual process for each VM</li><li>Guest Customization Specification is tied to a single vCenter Server which reduces scalability</li><li>Multiple VMs require multiple iterations of the same manual process</li></ul>
</div></div>



<h3 class="wp-block-heading">Deploy VMs via Ansible</h3>



<p>Ansible communicates with an OS via SSH on Linux, and via WinRM on Windows. It has different modules that can be used to communicate with different providers, such as AWS, GCP, and yes, VMware.</p>



<p><strong>Pros:</strong></p>



<ul><li>Infrastructure is defined in code</li><li>Excellent at ensuring desired state configuration of </li><li>Multi-os, and multi-cloud support</li></ul>



<p><strong>Cons:</strong></p>



<ul><li>This could end up being a bit of a holy war, but I consider it a con that Ansible requires different modules to connect to different cloud providers. They are maintained by different teams and individuals, and end up working differently than each other.</li></ul>



<h3 class="wp-block-heading">Deploy VMs using Terraform</h3>



<p>Terraform, similarly to Ansible, is able to communicate with Linux via SSH and Windows via WinRM. Where it differs, is it&#8217;s ability to communicate with cloud providers such as AWS, GCP, Azure, and VMware. Terraform uses the concept of &#8220;Providers&#8221;, with a number of them being maintained by Hashicorp, and a number of them being maintained by the community. In addition to cloud providers, they also have providers that allow for configuration of networking hardware, storage, databases, monitoring, DNS systems, and many more, all using the same structure in your code.</p>



<h2 class="wp-block-heading">Terraform Component Overview</h2>



<p>Few points to get us started here:</p>



<ul><li>Terraform will look in a directory for all files that have the extension of .tf, and .auto.tfvars</li><li>Terraform configuration files are written in <a rel="noreferrer noopener" href="https://www.terraform.io/docs/configuration/syntax.html" target="_blank">a language called HCL</a>, but can also be written in JSON.</li><li>Terraform uses the concept of blocks, I&#8217;ll go through them below</li></ul>



<h3 class="wp-block-heading">Resource Block</h3>



<p><a rel="noreferrer noopener" href="https://www.terraform.io/docs/configuration/resources.html" target="_blank">Hashicorp defines resources</a> as <em>the most important element in the Terraform language. Each resource block describes one or more infrastructure objects, such as virtual networks, compute instances, or higher-level components such as DNS records.</em> </p>



<p>In our example, we will be working with the resource type &#8220;vsphere_virtual_machine&#8221; that is defined by the vSphere provider. This resource block contains all information needed to provision and customize a new VM.</p>



<h3 class="wp-block-heading">Provider Block</h3>



<p>We&#8217;ll be working with the vSphere provider in this project. Providers have two main functions we should keep in mind when using Terraform with VMware.</p>



<ul><li>They define parameters used to connect to vCenter</li><li>They expose additional resources we can use. Most notably, the vsphere_virtual_machine resource.</li></ul>



<p><a href="https://www.terraform.io/docs/configuration/providers.html" target="_blank" rel="noreferrer noopener">Hashicorp Provider Documentation</a></p>



<h3 class="wp-block-heading">Data Source Blocks</h3>



<p>Hashicorp tells us that &#8220;<em><em>Data sources</em>&nbsp;allow data to be fetched or computed for use elsewhere in Terraform configuration. Use of data sources allows a Terraform configuration to make use of information defined outside of Terraform, or defined by another separate Terraform configuration</em>&#8221; and that <em>&#8220;Each&nbsp;provider&nbsp;may offer data sources alongside its set of&nbsp;resource types&#8221;</em>. </p>



<p>To say this &#8220;cloud agnostically&#8221;, data sources allow us to fetch information from a provider (whether it be something like AWS, GCP, Azure, or vSphere), and use that information in a resource.</p>



<p>To say this in &#8220;VMware Speak&#8221;, we use data sources to pull information like a datacenter, cluster, datastore, or port group from a vCenter, and use it to build a VM.</p>



<h3 class="wp-block-heading">Input Variable Block</h3>



<p>Hashicorp&#8217;s documentation says that Input Variables <em>&#8220;serve as parameters for a Terraform module, allowing aspects of the module to be customized without altering the module&#8217;s own source code, and allowing modules to be shared between different configurations</em>&#8220;. To say this another way, input variables end up working like parameters added on the command line on a script.</p>



<h2 class="wp-block-heading">Examples</h2>



<p>Let&#8217;s put all of this together. I&#8217;ll give you two examples here, one for setting up a Linux VM and one for a Windows VM.</p>



<h3 class="wp-block-heading">Provision Linux VM with Terraform</h3>



<p>The three files below are required for this project, and can be found in the <a href="https://github.com/jonhowe/Virtjunkie.com/tree/master/Terraform" target="_blank" rel="noreferrer noopener">github repository</a>.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">├── main.tf
├── variables.tf
└── homelab.auto.tfvars</pre>



<h4 class="wp-block-heading">Quick Start</h4>



<p>Run the following commands to get started!</p>



<pre class="urvanov-syntax-highlighter-plain-tag">git clone https://github.com/jonhowe/Virtjunkie.com.git
cd Virtjunkie.com/Terraform/SingleLinuxVM
terraform init
terraform plan
terraform apply</pre>



<p>Running <strong><code>terraform init</code> </strong>will set up the Terraform project. It will download any required modules and plugins for the project to be created. It will store all of it&#8217;s files in a hidden directory called &#8220;.terraform&#8221;.</p>



<p>The command <code><strong>terraform plan</strong></code> looks at the destination and determines what needs to change. Optionally, you can have Terraform store this &#8220;plan&#8221; in a file to be used at a later time. To do this, you&#8217;ll run this command: <code><strong>terraform plan -out myplan.tfplan</strong></code>. The extension and file name are not important.</p>



<p>Finally, the command <code><strong>terraform apply</strong></code> is used to make changes to the environment that were determined in the &#8220;plan&#8221; step. Optionally, you can tell terraform to &#8220;apply&#8221; based on the output. To do this, you&#8217;ll run the following command: <code><strong>terraform apply myplan.tfplan</strong></code>. This isn&#8217;t necessary for a single VM deployment, but if you are using automation, or deploying multiple VMs, it is more important.</p>



<h4 class="wp-block-heading">main.tf</h4>



<p>As the name states, this is the main file in the project. It contains the provider, data source, and resource blocks.</p>



<p>The provider block simply is pretty self explanatory. If this is your first time looking at a Terraform file, you&#8217;ll probably be interested in the var.&#8221;whatever&#8221; lines. In the provider block, there&#8217;s a variable in the variables.tf file called vsphere_user (and the others as well). The &#8220;var.&#8221; prefix tells us that we should look for this variable definition in an input variables block.</p>



<p>The data blocks take raw data from the vSphere environment (datacenter, datastore, cluster, and port group) and store them in variables used for building a VM. </p>



<p>To understand this a bit more, please take a look at the picture below. We are creating a variable called <strong><code>datacenter_id</code></strong> on line 19 and assigning it the value <strong><code>data.vsphere_datacenter.dc.id</code></strong>. Understanding this concept is key to understanding how Terraform creates and consumes variables. The below image will elaborate a bit. The value of <strong><code>data.vsphere_datacenter.dc.id</code></strong> is returned from the datacenter object in the vCenter Server.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="775" height="368" src="https://www.virtjunkie.com/wp-content/uploads/2020/04/terraform-config.png" alt="" class="wp-image-1228" srcset="/wp-content/uploads/2020/04/terraform-config.png 775w, /wp-content/uploads/2020/04/terraform-config-300x142.png 300w, /wp-content/uploads/2020/04/terraform-config-768x365.png 768w" sizes="(max-width: 775px) 100vw, 775px" /></figure>



<p>I&#8217;ll be comparing the way that Terraform blocks work together to the way that a programming function works. I&#8217;ll be using the following pseudocode to show similarities. The main.tf file, alongside with the blocks it contains would correspond with the area below:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="797" height="276" src="https://www.virtjunkie.com/wp-content/uploads/2020/04/terraform-main.png" alt="" class="wp-image-1236" srcset="/wp-content/uploads/2020/04/terraform-main.png 797w, /wp-content/uploads/2020/04/terraform-main-300x104.png 300w, /wp-content/uploads/2020/04/terraform-main-768x266.png 768w" sizes="(max-width: 797px) 100vw, 797px" /></figure>



<p><strong>Line 40 &#8211; Resource block begins</strong><br>Now that we understand how to reference values from input and data variables, most of this should be pretty clear. The one area I want to spend a little bit of time on is the customize block, starting on line 67. In this example, we are simply setting the host name and the domain inside of the provisioned VM. However, there you could set static networking, dns and the time zone as well, if you like.</p>



<p>Here&#8217;s the code for the main.tf file. It&#8217;s also <a href="https://github.com/jonhowe/Virtjunkie.com/blob/master/Terraform/SingleLinuxVM/main.tf" target="_blank" rel="noreferrer noopener">available on github</a>.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">#The variables are all defined in the variables.tf file. The values assigned to the variables are set in the auto.tfvars file

provider &quot;vsphere&quot; {
  #https://www.terraform.io/docs/providers/vsphere/index.html
  user                 = var.vsphere_user
  password             = var.vsphere_password
  vsphere_server       = var.vsphere_server
  allow_unverified_ssl = true
}

data &quot;vsphere_datacenter&quot; &quot;dc&quot; {
  #https://www.terraform.io/docs/providers/vsphere/d/datacenter.html
  name = var.datacenter
}

data &quot;vsphere_datastore&quot; &quot;datastore&quot; {
  #https://www.terraform.io/docs/providers/vsphere/d/datastore.html
  name          = var.datastore
  datacenter_id = data.vsphere_datacenter.dc.id
}

data &quot;vsphere_compute_cluster&quot; &quot;cluster&quot; {
  #https://www.terraform.io/docs/providers/vsphere/d/compute_cluster.html
  var.cluster
  datacenter_id = data.vsphere_datacenter.dc.id
}

data &quot;vsphere_network&quot; &quot;network&quot; {
  #https://www.terraform.io/docs/providers/vsphere/d/network.html
  name          = var.portgroup
  datacenter_id = data.vsphere_datacenter.dc.id
}

data &quot;vsphere_virtual_machine&quot; &quot;template&quot; {
  #https://www.terraform.io/docs/providers/vsphere/d/virtual_machine.html
  name          = var.template_name
  datacenter_id = data.vsphere_datacenter.dc.id
}

resource &quot;vsphere_virtual_machine&quot; &quot;vm&quot; {
  #https://www.terraform.io/docs/providers/vsphere/r/virtual_machine.html
  name             = var.vm_name
  resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
  datastore_id     = data.vsphere_datastore.datastore.id

  num_cpus = var.vcpu_count
  memory   = var.memory
  guest_id = data.vsphere_virtual_machine.template.guest_id

  scsi_type = data.vsphere_virtual_machine.template.scsi_type

  network_interface {
    network_id   = data.vsphere_network.network.id
    adapter_type = data.vsphere_virtual_machine.template.network_interface_types&amp;#91;0]
  }

  disk {
    label            = &quot;disk0&quot;
    size             = data.vsphere_virtual_machine.template.disks.0.size
    eagerly_scrub    = data.vsphere_virtual_machine.template.disks.0.eagerly_scrub
    thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
  }

  clone {
    template_uuid = data.vsphere_virtual_machine.template.id

    customize {
      #https://www.terraform.io/docs/providers/vsphere/r/virtual_machine.html#linux-customization-options
      linux_options {
        host_name = var.vm_name
        domain    = var.domain_name
      }

      #This example uses DHCP. To switch to static IP addresses, comment the line below...
      network_interface {}

      #... and uncomment this bloc
      /*
      network_interface {
        ipv4_address = var.vm_ip
        ipv4_netmask = var.vm_cidr
    }
      ipv4_gateway = var.default_gw
      dns_server_list = &amp;#91;&quot;1.2.3.4&quot;]
    */

    }

  }
}</pre>



<h4 class="wp-block-heading">variables.tf</h4>



<p>Terraform can be most easily understood by comparing the structure of a project to a programming function. The main file is the body of the function, and it consumes values of variables to &#8220;do stuff&#8221;. Most programming languages require us to declare a variable before we can assign a value to it or use it. That&#8217;s really all the input variables block is for. In the example below, we are defining the variable name, providing a description for it, and assigning a default value.</p>



<p>If you want to use a pseudocode example, the variable definition below is the function of the input variable block, and the function of the entire variables.tf file</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="795" height="294" src="https://www.virtjunkie.com/wp-content/uploads/2020/04/terraform-variables-1.png" alt="" class="wp-image-1232" srcset="/wp-content/uploads/2020/04/terraform-variables-1.png 795w, /wp-content/uploads/2020/04/terraform-variables-1-300x111.png 300w, /wp-content/uploads/2020/04/terraform-variables-1-768x284.png 768w" sizes="(max-width: 795px) 100vw, 795px" /></figure>



<p>Here&#8217;s the code for the variables.tf file, which is also <a href="https://github.com/jonhowe/Virtjunkie.com/blob/master/Terraform/SingleLinuxVM/variables.tf" target="_blank" rel="noreferrer noopener">available on github</a>.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">variable &quot;vsphere_server&quot; {
  description = &quot;vsphere server for the environment - EXAMPLE: vcenter01.hosted.local&quot;
  default     = &quot;vcenter.corp.lab&quot;
}

variable &quot;vsphere_user&quot; {
  description = &quot;vsphere server for the environment - EXAMPLE: vsphereuser&quot;
  default     = &quot;administrator@vsphere.local&quot;
}

variable &quot;vsphere_password&quot; {
  description = &quot;vsphere server password for the environment&quot;
  default     = &quot;VMware1!&quot;
}

variable &quot;adminpassword&quot; { 
    default = &quot;terraform&quot; 
    description = &quot;Administrator password for windows builds&quot;
}

variable &quot;datacenter&quot; { 
    default = &quot;Datacenter&quot;
    description = &quot;Datacenter name in vCenter&quot;
}

variable &quot;datastore&quot; { 
    default = &quot;vsanDatastore&quot; 
    description = &quot;datastore name in vCenter&quot;
}

variable &quot;cluster&quot; { 
    default = &quot;Cluster&quot; 
    description = &quot;Cluster name in vCenter&quot;
}

variable &quot;portgroup&quot; { 
    default = &quot;VM Network&quot; 
    description = &quot;Port Group new VM(s) will use&quot;
}

variable &quot;domain_name&quot; { 
    default = &quot;contoso.lan&quot;
    description = &quot;Domain Search name&quot;
}
variable &quot;default_gw&quot; { 
    default = &quot;172.16.1.1&quot; 
    description = &quot;Default Gateway&quot;
}

variable &quot;template_name&quot; { 
    default = &quot;Windows2019&quot; 
    description = &quot;VMware Template Name&quot;
}

variable &quot;vm_name&quot; { 
    default = &quot;WS19-1&quot; 
    description = &quot;New VM Name&quot;

}

variable &quot;vm_ip&quot; { 
    default = &quot;172.16.1.150&quot; 
    description = &quot;IP Address to assign to VM&quot;
}

variable &quot;vm_cidr&quot; { 
    default = 24 
    description = &quot;CIDR Block for VM&quot;
}

variable &quot;vcpu_count&quot; { 
    default = 1 
    description = &quot;How many vCPUs do you want?&quot;
}

variable &quot;memory&quot; { 
    default = 1024 
    description = &quot;RAM in MB&quot;
}</pre>



<h4 class="wp-block-heading">homelab.auto.tfvars</h4>



<p>If you&#8217;ve been reading in order up to this point, you understand the programming function analogy. Ansible will look in it&#8217;s directory for a file with the extension of .auto.tfvars. It will use it to assign values to input variables that are defined in the variables.tf file.</p>



<p>Below is a pseudo code example that shows how we&#8217;d compare terraform to a function in a conventional programming language.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="787" height="303" src="https://www.virtjunkie.com/wp-content/uploads/2020/04/terraform-tfvars.png" alt="" class="wp-image-1234" srcset="/wp-content/uploads/2020/04/terraform-tfvars.png 787w, /wp-content/uploads/2020/04/terraform-tfvars-300x116.png 300w, /wp-content/uploads/2020/04/terraform-tfvars-768x296.png 768w" sizes="(max-width: 787px) 100vw, 787px" /></figure>



<p>Below is the tfvars file I use in my home lab, and for your reference, it&#8217;s also <a href="https://github.com/jonhowe/Virtjunkie.com/blob/master/Terraform/SingleLinuxVM/homelab.auto.tfvars" target="_blank" rel="noreferrer noopener">available on github</a>.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">vsphere_server = &quot;vcenter.home.lab&quot;

vsphere_user = &quot;administrator@vsphere.local&quot;

vsphere_password = &quot;VMware1!&quot;

adminpassword = &quot;terraform&quot; 

datacenter = &quot;Datacenter&quot;

datastore = &quot;vsanDatastore&quot; 

cluster = &quot;Cluster&quot;

portgroup = &quot;100-LabNetwork&quot; 

domain_name = &quot;home.lab&quot;

default_gw = &quot;172.16.1.1&quot; 

template_name = &quot;Ubuntu18&quot; 

vm_name = &quot;Ubuntu18-1&quot; 

vm_ip = &quot;172.16.1.150&quot;

vm_cidr = 24

vcpu_count = 1

memory = 1024</pre>



<h3 class="wp-block-heading">Provision Windows VM with Terraform</h3>



<p>Since provisioning a Windows and Linux VM share literally everything in a virtual environment with exception of the OS itself, there&#8217;s not a whole lot that&#8217;s different in provisioning Windows VMs. The one are that is different is the Customize block inside of the Resource block.</p>



<p>We are handling this the exact same as the Linux VM, however, we have a handful of options we can add, such as</p>



<ul><li>Join a domain</li><li>Execute a list of commands</li><li>Add a product key</li><li>Enable auto login for a specified amount of logins</li><li>Supply your own SysPrep file</li></ul>



<p>Here&#8217;s the code, but all files are <a href="https://github.com/jonhowe/Virtjunkie.com/tree/master/Terraform/SingleWindowsVM" target="_blank" rel="noreferrer noopener">stored on Github</a>.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">resource &quot;vsphere_virtual_machine&quot; &quot;vm&quot; {
  name             = var.vm_name
  resource_pool_id = data.vsphere_compute_cluster.cluster.resource_pool_id
  datastore_id     = data.vsphere_datastore.datastore.id

  num_cpus = var.vcpu_count
  memory   = var.memory
  guest_id = data.vsphere_virtual_machine.template.guest_id

  scsi_type = data.vsphere_virtual_machine.template.scsi_type

  network_interface {
    network_id   = data.vsphere_network.network.id
    adapter_type = data.vsphere_virtual_machine.template.network_interface_types&amp;#91;0]
  }

  disk {
    label            = &quot;disk0&quot;
    size             = data.vsphere_virtual_machine.template.disks.0.size
    eagerly_scrub    = data.vsphere_virtual_machine.template.disks.0.eagerly_scrub
    thin_provisioned = data.vsphere_virtual_machine.template.disks.0.thin_provisioned
  }

  clone {
    template_uuid = data.vsphere_virtual_machine.template.id

    customize {
      #https://www.terraform.io/docs/providers/vsphere/r/virtual_machine.html#windows-customization-options
      windows_options {
        computer_name  = var.vm_name
        admin_password = var.adminpassword
        /*
        join_domain = &quot;cloud.local&quot;
	      domain_admin_user = &quot;administrator@cloud.local&quot;
	      domain_admin_password = &quot;password&quot;
        run_once_command_list = &amp;#91;

        ]
        */
      }
      network_interface {}

      /*
      network_interface {
        ipv4_address = var.vm_ip
        ipv4_netmask = var.vm_cidr
      }
      ipv4_gateway = var.default_gw
      dns_server_list = &amp;#91;&quot;1.2.3.4&quot;]
      */
    }
  }
}</pre>



<h2 class="wp-block-heading">References</h2>



<p>The following resources were helpful for me getting started, and I suggest you take a look at them as well.</p>



<p>The Terraform documentation is the best place to start (<a rel="noreferrer noopener" href="https://www.terraform.io/docs/cli-index.html" target="_blank">link</a>)<br>Dmitry Teslya has a great article that got me started here, but like the packer article he created, wasn&#8217;t working for me. Highly recommend this one (<a rel="noreferrer noopener" href="https://dteslya.engineer/automation/2019-01-21-creating_vms_with_terraform/" target="_blank">link</a>)<br></p>



<h2 class="wp-block-heading">What&#8217;s next?</h2>



<p>Good Question! At this point, I&#8217;ve written <a href="https://www.virtjunkie.com/vmware-template-packer/" target="_blank" rel="noreferrer noopener">about how to manage images (read: vmware templates) using Packer</a>. I&#8217;ve written this article, which speaks to how to deploy the VMs. The next things I&#8217;ll speak about are:</p>



<ul><li><a href="https://www.virtjunkie.com/vmware-provisioning-using-hashicorp-terraform-part-2/" target="_blank" rel="noreferrer noopener">Write our own Terraform Module, store it in Github, and use that, instead of a full Terraform project, so we can deploy multiple VMs, from different templates, all at once.</a></li><li>Use Ansible to configure our newly provisioned VMs</li><li>Wrap the Terraform VM Deployment process, as well as the Ansible VM configuration process together into a single process you execute once</li><li>Use Ansible to do a greenfield deployment of a vSphere environment</li></ul>



<p></p>
<p>The post <a href="/2020/04/22/vmware-provisioning-using-hashicorp-terraform/">VMware Provisioning using Hashicorp Terraform</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2020/04/22/vmware-provisioning-using-hashicorp-terraform/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Poor Man&#8217;s AutoDeploy Using Custom Kickstart, and Python</title>
		<link>/2020/04/09/poor-mans-autodeploy/</link>
					<comments>/2020/04/09/poor-mans-autodeploy/#comments</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Thu, 09 Apr 2020 13:00:00 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=1107</guid>

					<description><![CDATA[<p>I recently encountered a situation where I needed to provision hundreds of ESXi hosts. The thing is, there was no vSphere Autodeploy, or HPE Synergy Image Streamer, and no ability to (long story, trust me here). No way I'm going to manually provision all of those hosts by hand, so what's a guy to do?!</p>
<p>While I designed this solution to work with hundreds of production ESXi hosts, there's nothing from preventing you from using this method in smaller production environments, or even your own home lab.</p>
<p>The post <a href="/2020/04/09/poor-mans-autodeploy/">Poor Man&#8217;s AutoDeploy Using Custom Kickstart, and Python</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I recently encountered a situation where I needed to provision hundreds of ESXi hosts. The thing is, there was no vSphere Autodeploy, or HPE Synergy Image Streamer, and no ability to (long story, trust me here) spin them up. No way I&#8217;m going to manually provision all of those hosts by hand, so what&#8217;s a guy to do?!</p>



<p>This solution will automatically provision ESXi hosts and &#8220;get them on the network&#8221; so you can add them to vCenter just by using tools that VMware gives us, and a little bit of creativity.</p>



<p>While I designed this solution to work with hundreds of production ESXi hosts, there&#8217;s nothing from preventing you from using this method in smaller production environments, or even your own home lab.</p>



<span id="more-1107"></span>



<h2 class="wp-block-heading">Overview</h2>



<p>At a very high level, the process works as follows.. The physical server boots from an ISO, USB Image, or even CD/DVD, if you&#8217;re into that sort of thing. The ESXi image on this media will contain a slightly customized ESXi image that looks for a kickstart file pulls the rest of the install instructions from a kickstart file on a web server. This kickstart fill will handle the silent install of ESXi, reboot into the newly installed OS, set a few settings, then download a CSV that contains ESXi host configuration info (such as host name, IP, and Default Gateway), and a python script that will send esxcli commands to the host in order to configure networking.</p>



<h3 class="wp-block-heading">Diagram</h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="412" src="https://new.virtjunkie.com/wp-content/uploads/2020/04/Poor-Mans-AutoDeploy-1024x412.jpeg" alt="" class="wp-image-1146" srcset="/wp-content/uploads/2020/04/Poor-Mans-AutoDeploy-1024x412.jpeg 1024w, /wp-content/uploads/2020/04/Poor-Mans-AutoDeploy-300x121.jpeg 300w, /wp-content/uploads/2020/04/Poor-Mans-AutoDeploy-768x309.jpeg 768w, /wp-content/uploads/2020/04/Poor-Mans-AutoDeploy-1536x617.jpeg 1536w, /wp-content/uploads/2020/04/Poor-Mans-AutoDeploy-2048x823.jpeg 2048w, /wp-content/uploads/2020/04/Poor-Mans-AutoDeploy-1568x630.jpeg 1568w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Modified Boot.cfg file</h2>



<p>First and foremost, I need to emphasize the fact that there are two places you need to put your boot.cfg file. One in the root of the filesystem you have on your media, and one in the efi folder. This file is read during the boot process and instructs ESXi on how to boot. We care about the line that begins with <strong>kernelopt=</strong>. By default, this line tells ESXi to start with the traditional GUI installer which we definitely don&#8217;t want. Instead, we&#8217;ll modify it to tell the installer to look for a kickstart file on a web server, and will set static networking for the host.</p>



<p>At a high level, the modifications here accomplish the following:</p>



<ol><li>Instruct the ESXi host to find a kickstart file on a web server</li><li>Set a static IP, netmask, default gateway, and nameserver to use prior to automatically configuring the host</li></ol>



<h3 class="wp-block-heading">boot.cfg code</h3>



<p><a href="https://github.com/jonhowe/Virtjunkie.com/tree/master/PoorMansAutoDeploy/esxi-iso" target="_blank" rel="noreferrer noopener">Here&#8217;s a link to the code</a></p>



<pre class="urvanov-syntax-highlighter-plain-tag">bootstate=0
title=Loading ESXi installer
timeout=5
prefix=
kernel=/b.b00
#kernelopt=cdromBoot runweasel
kernelopt=ks=http://vmware-ks.home.lab:8123/files/VMware/ks/ks.cfg nameserver=192.168.1.60 ip=192.168.1.5 netmask=255.255.255.0 gateway=192.168.1.1
modules=/jumpstrt.gz --- /useropts.gz --- /features.gz --- /k.b00 --- /chardevs.b00 --- /user.b00 --- /procfs.b00 --- /uc_intel.b00 --- /uc_amd.b00 --- /uc_hygon.b00 --- /vmx.v00 --- /vim.v00 --- /sb.v00 --- /s.v00 --- /ata_liba.v00 --- /ata_pata.v00 --- /ata_pata.v01 --- /ata_pata.v02 --- /ata_pata.v03 --- /ata_pata.v04 --- /ata_pata.v05 --- /ata_pata.v06 --- /ata_pata.v07 --- /block_cc.v00 --- /bnxtnet.v00 --- /bnxtroce.v00 --- /brcmfcoe.v00 --- /char_ran.v00 --- /ehci_ehc.v00 --- /elxiscsi.v00 --- /elxnet.v00 --- /hid_hid.v00 --- /i40en.v00 --- /iavmd.v00 --- /igbn.v00 --- /ima_qla4.v00 --- /ipmi_ipm.v00 --- /ipmi_ipm.v01 --- /ipmi_ipm.v02 --- /iser.v00 --- /ixgben.v00 --- /lpfc.v00 --- /lpnic.v00 --- /lsi_mr3.v00 --- /lsi_msgp.v00 --- /lsi_msgp.v01 --- /lsi_msgp.v02 --- /misc_cni.v00 --- /misc_dri.v00 --- /mtip32xx.v00 --- /ne1000.v00 --- /nenic.v00 --- /net_bnx2.v00 --- /net_bnx2.v01 --- /net_cdc_.v00 --- /net_cnic.v00 --- /net_e100.v00 --- /net_e100.v01 --- /net_enic.v00 --- /net_fcoe.v00 --- /net_forc.v00 --- /net_igb.v00 --- /net_ixgb.v00 --- /net_libf.v00 --- /net_mlx4.v00 --- /net_mlx4.v01 --- /net_nx_n.v00 --- /net_tg3.v00 --- /net_usbn.v00 --- /net_vmxn.v00 --- /nfnic.v00 --- /nhpsa.v00 --- /nmlx4_co.v00 --- /nmlx4_en.v00 --- /nmlx4_rd.v00 --- /nmlx5_co.v00 --- /nmlx5_rd.v00 --- /ntg3.v00 --- /nvme.v00 --- /nvmxnet3.v00 --- /nvmxnet3.v01 --- /ohci_usb.v00 --- /pvscsi.v00 --- /qcnic.v00 --- /qedentv.v00 --- /qfle3.v00 --- /qfle3f.v00 --- /qfle3i.v00 --- /qflge.v00 --- /sata_ahc.v00 --- /sata_ata.v00 --- /sata_sat.v00 --- /sata_sat.v01 --- /sata_sat.v02 --- /sata_sat.v03 --- /sata_sat.v04 --- /scsi_aac.v00 --- /scsi_adp.v00 --- /scsi_aic.v00 --- /scsi_bnx.v00 --- /scsi_bnx.v01 --- /scsi_fni.v00 --- /scsi_hps.v00 --- /scsi_ips.v00 --- /scsi_isc.v00 --- /scsi_lib.v00 --- /scsi_meg.v00 --- /scsi_meg.v01 --- /scsi_meg.v02 --- /scsi_mpt.v00 --- /scsi_mpt.v01 --- /scsi_mpt.v02 --- /scsi_qla.v00 --- /sfvmk.v00 --- /shim_isc.v00 --- /shim_isc.v01 --- /shim_lib.v00 --- /shim_lib.v01 --- /shim_lib.v02 --- /shim_lib.v03 --- /shim_lib.v04 --- /shim_lib.v05 --- /shim_vmk.v00 --- /shim_vmk.v01 --- /shim_vmk.v02 --- /smartpqi.v00 --- /uhci_usb.v00 --- /usb_stor.v00 --- /usbcore_.v00 --- /vmkata.v00 --- /vmkfcoe.v00 --- /vmkplexe.v00 --- /vmkusb.v00 --- /vmw_ahci.v00 --- /xhci_xhc.v00 --- /elx_esx_.v00 --- /btldr.t00 --- /esx_dvfi.v00 --- /esx_ui.v00 --- /esxupdt.v00 --- /weaselin.t00 --- /lsu_hp_h.v00 --- /lsu_inte.v00 --- /lsu_lsi_.v00 --- /lsu_lsi_.v01 --- /lsu_lsi_.v02 --- /lsu_lsi_.v03 --- /lsu_lsi_.v04 --- /lsu_smar.v00 --- /native_m.v00 --- /qlnative.v00 --- /rste.v00 --- /vmware_e.v00 --- /vsan.v00 --- /vsanheal.v00 --- /vsanmgmt.v00 --- /tools.t00 --- /xorg.v00 --- /imgdb.tgz --- /imgpayld.tgz
build=
updated=0</pre>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Kickstart file (ks.cfg)</h2>



<p>The kickstart file provides the ESXi installer with all the information it needs to perform the installation without manual intervention. We are handling this in two stages by using the firstboot parameter.</p>



<h3 class="wp-block-heading">Stage 1</h3>



<p>Handles the installation of ESXi to physical hardware. The following tasks are completed:</p>



<ol><li>Accept EULA</li><li>Select disk for ESXi to be installed to</li><li>Set root password</li><li>Set IP to be used on first boot (Default is DHCP, but the code to use static is included/commented in the code)</li></ol>



<h3 class="wp-block-heading">Stage 2</h3>



<p>All of stage two is executed in the newly installed ESXi OS using the firstboot parameter. The following tasks are completed:</p>



<ol><li>Enable SSH and ESXi Shell</li><li>Disable warnings for #1</li><li>Disable ESXi Firewall so we can use wget</li><li>Using wget, download the following files<ol><li>ListOfHosts.csv</li><li>configurehost.py</li></ol></li><li>Set the execution bit on the python script</li><li>Execute the python script</li></ol>



<h3 class="wp-block-heading">ks.cfg code</h3>



<p><a href="https://github.com/jonhowe/Virtjunkie.com/blob/master/PoorMansAutoDeploy/ks.cfg" target="_blank" rel="noreferrer noopener">Here&#8217;s a link to the code</a></p>



<pre class="urvanov-syntax-highlighter-plain-tag">#__      ___      _       _             _    _      
#\ \    / (_)    | |     | |           | |  (_)     
# \ \  / / _ _ __| |_    | |_   _ _ __ | | ___  ___ 
#  \ \/ / | | '__| __|   | | | | | '_ \| |/ / |/ _ \
#   \  /  | | |  | || |__| | |_| | | | |   &amp;lt;| |  __/
#    \/   |_|_|   \__\____/ \__,_|_| |_|_|\_\_|\___|

#Jon Howe
#https://www.virtjunkie.com/Poor-Mans-AutoDeploy
#https://github.com/jonhowe/Virtjunkie.com/tree/master/PoorMansAutoDeploy

#  _____ _                     __            _____           _        _ _       _   _             
# / ____| |                   /_ |          |_   _|         | |      | | |     | | (_)            
#| (___ | |_ __ _  __ _  ___   | |  ______    | |  _ __  ___| |_ __ _| | | __ _| |_ _  ___  _ __  
# \___ \| __/ _` |/ _` |/ _ \  | | |______|   | | | '_ \/ __| __/ _` | | |/ _` | __| |/ _ \| '_ \ 
# ____) | || (_| | (_| |  __/  | |           _| |_| | | \__ \ || (_| | | | (_| | |_| | (_) | | | |
#|_____/ \__\__,_|\__, |\___|  |_|          |_____|_| |_|___/\__\__,_|_|_|\__,_|\__|_|\___/|_| |_|
#                  __/ |                                                                          
#                 |___/                                                                           

# Accept the VMware End User License Agreement
vmaccepteula

# The install media is in the CD-ROM drive
#   This was the hardest part for some reason. I was installing from a USB drive TO a separate USB drive.
#   https://docs.vmware.com/en/VMware-vSphere/6.7/com.vmware.esxi.upgrade.doc/GUID-61A14EBB-5CF3-43EE-87EF-DB8EC6D83698.html
#   https://docs.vmware.com/en/VMware-vSphere/6.7/com.vmware.esxi.upgrade.doc/GUID-E7274FBA-CABC-43E8-BF74-2924FD3EFE1E.html
#   If you find the wrong device is being selected, you can hit CTRL+F1 during the install, log in (root/&amp;#91;no password]) and enter
#   the following command to get a list of the available devices:
#   localcli storage core device list
install --disk=/vmfs/devices/disks/mpx.vmhba33:C0:T0:L0 --overwritevmfs --novmfsondisk

# Set the root password for the DCUI and Tech Support Mode
rootpw VMware1!

### Temporary Network Configuration
#   Keep in mind, this is temporary. The actual IP address will be set in Stage 2
#   We don't even technically need this, but I wanted to include it in case we need network connectivity in Stage 1

# Set the network to DHCP on the first network adapter
network --bootproto=dhcp --device=vmnic0
# ... or if you want, you can set this to static
# network --bootproto=static --ip=192.168.30.13 --netmask=255.255.255.0 --gateway=192.168.30.1 --hostname=esxi1-mgmt.home.lab --nameserver=192.168.0.1 --addvmportgroup=1

reboot

#  _____ _                     ___              _____ _                 _         _____             __ _       
# / ____| |                   |__ \            / ____(_)               | |       / ____|           / _(_)      
#| (___ | |_ __ _  __ _  ___     ) |  ______  | (___  _ _ __ ___  _ __ | | ___  | |     ___  _ __ | |_ _  __ _ 
# \___ \| __/ _` |/ _` |/ _ \   / /  |______|  \___ \| | '_ ` _ \| '_ \| |/ _ \ | |    / _ \| '_ \|  _| |/ _` |
# ____) | || (_| | (_| |  __/  / /_            ____) | | | | | | | |_) | |  __/ | |___| (_) | | | | | | | (_| |
#|_____/ \__\__,_|\__, |\___| |____|          |_____/|_|_| |_| |_| .__/|_|\___|  \_____\___/|_| |_|_| |_|\__, |
#                  __/ |                                         | |                                      __/ |
#                 |___/                                          |_|                                     |___/ 

%firstboot --interpreter=busybox

# enable &amp;amp; start SSH
vim-cmd hostsvc/enable_ssh
vim-cmd hostsvc/start_ssh

# enable &amp;amp; start ESXi Shell
vim-cmd hostsvc/enable_esx_shell
vim-cmd hostsvc/start_esx_shell

# Suppress ESXi Shell warning
esxcli system settings advanced set -o /UserVars/SuppressShellWarning -i 1

#Temporarily disable the firewall so we can grab a couple files using wget
esxcli network firewall set --enabled false

# Download Host Config CSV, host configuration script, and execute the host configuration script
wget -O ListOfHosts.csv http://jondesktop.home.lan:8123/files/VMware/ks/ListOfHosts.csv
wget -O configurehost.py http://jondesktop.home.lan:8123/files/VMware/ks/configurehost.py
chmod u+x configurehost.py
/bin/python configurehost.py

#Re-enable the firewall
esxcli network firewall set --enabled true</pre>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Host Detail Spreadsheet</h2>



<p>I like to have all, or as much configuration as possible defined in a document, and consume that as a part of the provisioning process. In this case, since I&#8217;m executing this on an ESXi host using the version of python that is available to the host, I&#8217;m simply using a CSV file. This strikes a healthy balance between usability and functionality.<br><br><a rel="noreferrer noopener" href="https://github.com/jonhowe/Virtjunkie.com/blob/master/PoorMansAutoDeploy/ListOfHosts.csv" target="_blank">Here&#8217;s a link to the CSV on my github account</a></p>



<p>The columns are as follows:</p>



<figure class="wp-block-table"><table><tbody><tr><td>Column A</td><td>ESXi Hostname</td></tr><tr><td>Column B</td><td>MAC Address of vmnic0</td></tr><tr><td>Column C</td><td>Desired Management IP Address (vmk0)</td></tr><tr><td>Column D</td><td>Subnet Mask for vmk0</td></tr><tr><td>Column E</td><td>Default Gateway for vmk0</td></tr><tr><td>Column F</td><td>VLAN Assigned to vmk0</td></tr></tbody></table><figcaption>Note: Columns have been converted to rows in this table. The actual representation is shown in the image below.</figcaption></figure>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="789" height="127" src="https://www.virtjunkie.com/wp-content/uploads/2020/04/image.png" alt="" class="wp-image-1137" srcset="/wp-content/uploads/2020/04/image.png 789w, /wp-content/uploads/2020/04/image-300x48.png 300w, /wp-content/uploads/2020/04/image-768x124.png 768w" sizes="(max-width: 789px) 100vw, 789px" /></figure>



<h2 class="wp-block-heading">configureHost.py</h2>



<p>Here&#8217;s where the magic comes in&#8230; Since ESXi is deployed with python, we can use it to parse a CSV file that has a list of all details for an ESXi host, and set the relevant details for the host.<br><a rel="noreferrer noopener" href="https://github.com/jonhowe/Virtjunkie.com/blob/master/PoorMansAutoDeploy/configurehost.py" target="_blank">Here&#8217;s a link to the code</a></p>



<p>In this very basic example, we are doing the following based on input in the CSV file:</p>



<ol><li>Set the hostname</li><li>Set the IP Address and Netmask of vmk0</li><li>Set the default gateway for the host</li><li>Set the VLAN for the management port group on vSwitch0</li></ol>
</div></div>



<h3 class="wp-block-heading">configureHost.py code</h3>



<pre class="urvanov-syntax-highlighter-plain-tag">#__      ___      _       _             _    _      
#\ \    / (_)    | |     | |           | |  (_)     
# \ \  / / _ _ __| |_    | |_   _ _ __ | | ___  ___ 
#  \ \/ / | | '__| __|   | | | | | '_ \| |/ / |/ _ \
#   \  /  | | |  | || |__| | |_| | | | |   &amp;lt;| |  __/
#    \/   |_|_|   \__\____/ \__,_|_| |_|_|\_\_|\___|
                                                  
#Jon Howe
#https://www.virtjunkie.com/Poor-Mans-AutoDeploy
#https://github.com/jonhowe/Virtjunkie.com/tree/master/PoorMansAutoDeploy

import os, csv, subprocess

CSVPATH = '/ListOfHosts.csv'

#Gets all mac addresses of interfaces
MAC=subprocess.check_output(&quot;esxcli network ip interface list |grep MAC | cut -d ' ' -f 6&quot;,shell=True)
                                                                                                                                                                                                                                                                                    
MACADDR = MAC.split()
print(&quot;MAC Addresses:&quot;)
print(MACADDR)

#Open the CSV file
with open(CSVPATH, 'rt') as csvFile:
        csvReader = csv.reader(csvFile)
        #Process the CSV file, row by row
        for csvRow in csvReader:
                #Check to see if the Mac Address of vmnic0 (IE: MACADDR&amp;#91;0]) matches the row in the CSV we are looking at
                if ((MACADDR&amp;#91;0]).decode('utf-8')) == csvRow&amp;#91;1]:
                        #print(&quot;esxcli system hostname set --fqdn=&quot; + csvRow&amp;#91;0])
                        #print(&quot;esxcli network ip interface ipv4 set --interface-name=vmk0 --ipv4=&quot; + csvRow&amp;#91;2] + &quot; --netmask=&quot; + csvRow&amp;#91;3] + &quot; --type=static&quot;)
                        
                        #Set the hostname to the value in the CSV
                        os.system(&quot;esxcli system hostname set --fqdn=&quot; + csvRow&amp;#91;0])
                        
                        #Set the IP Address and Netmask of vmk0
                        os.system(&quot;esxcli network ip interface ipv4 set --interface-name=vmk0 --ipv4=&quot; + csvRow&amp;#91;2] + &quot; --netmask=&quot; + csvRow&amp;#91;3] + &quot; --type=static&quot;)
                        
                        #Add the default gateway
                        os.system(&quot;esxcfg-route &quot; + csvRow&amp;#91;4])
                        
                        #Add the desired VLAN for the Management Network on the vSwitch that gets created by default (vSwitch0)
                        os.system(&quot;esxcfg-vswitch -p 'Management Network' -v &quot; + csvRow&amp;#91;5] + &quot; vSwitch0&quot;)</pre>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Web Server</h2>



<p>Since none of this works without a web server, we&#8217;ll need to make sure we have one available. My goal in creating this was to have the whole project be as portable as possible. To that effort, I use a small docker container I can start/stop on my laptop or workstation that hosts the required files, but there&#8217;s nothing preventing you from doing this on a production server as well. I&#8217;m using a container that has a nice graphical directory browser, but also allows for direct downloading of files. <a rel="noreferrer noopener" href="https://hub.docker.com/r/mohamnag/nginx-file-browser" target="_blank">Here&#8217;s a link to more information about this container</a></p>



<p>As a side note, in a <a rel="noreferrer noopener" href="https://www.virtjunkie.com/deploy-vcsa-via-powershell/" target="_blank">previous blog post, I spoke about deploying VCSA</a> based on properties in an Excel file. One of the prerequisites for this to work is to have a web server that hosts the ISO file. I use this same container to serve the files for that project.</p>



<h3 class="wp-block-heading">Docker Container</h3>



<p>The following snippet can be used to create a docker container to host the files required by this project.</p>



<pre class="urvanov-syntax-highlighter-plain-tag">docker run -p 8123:80 -v /storage/poormansautodeploy/ks/:/opt/www/files --name=filebrowser -d --restart unless-stopped --log-opt max-size=15m --log-opt max-file=2 mohamnag/nginx-file-browser</pre>



<h3 class="wp-block-heading">Directory structure</h3>



<pre class="urvanov-syntax-highlighter-plain-tag">ks
├── configurehost.py
├── ks.cfg
└── ListOfHosts.csv</pre>
</div></div>



<h3 class="wp-block-heading">Web Server In Action</h3>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="464" height="408" src="https://www.virtjunkie.com/wp-content/uploads/2020/04/image-1.png" alt="" class="wp-image-1159" srcset="/wp-content/uploads/2020/04/image-1.png 464w, /wp-content/uploads/2020/04/image-1-300x264.png 300w" sizes="(max-width: 464px) 100vw, 464px" /></figure>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Create ISO</h2>



<p>This is the process to create a custom ISO</p>
</div></div>



<pre class="urvanov-syntax-highlighter-plain-tag">genisoimage -relaxed-filenames -J -R -o &amp;#91;yourisoname].iso -b isolinux.bin -c boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -eltorito-alt-boot -e efiboot.img -no-emul-boot &amp;#91;path to extracted iso]</pre>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">References</h2>



<ul><li>I owe a big thank you to Andrew Dauncey (<a rel="noreferrer noopener" href="https://twitter.com/daunce_" target="_blank">twitter</a>, <a rel="noreferrer noopener" href="https://theoddangryshot.com/" target="_blank">blog</a>, <a rel="noreferrer noopener" href="https://github.com/daunce" target="_blank">github</a>). He created <a rel="noreferrer noopener" href="https://theoddangryshot.com/2016/09/07/esxi-kickstart-with-python/" target="_blank">a post</a> back in 2016 that accomplished something similar to this, but was no longer working with modern versions of vSphere. I updated the code to work with vSphere, and added some additional functionality. Thanks again Andrew!</li><li>As always, the VMware documentation is a good place to start. Here&#8217;s the documentation for 6.7 (<a rel="noreferrer noopener" href="https://docs.vmware.com/en/VMware-vSphere/6.7/com.vmware.esxi.upgrade.doc/GUID-870A07BC-F8B4-47AF-9476-D542BA53F1F5.html" target="_blank">link</a>) and here&#8217;s the documentation for 7.0 (<a href="https://docs.vmware.com/en/VMware-vSphere/7.0/com.vmware.esxi.upgrade.doc/GUID-870A07BC-F8B4-47AF-9476-D542BA53F1F5.html" target="_blank" rel="noreferrer noopener">link</a>)</li></ul>
</div></div>



<p></p>
<p>The post <a href="/2020/04/09/poor-mans-autodeploy/">Poor Man&#8217;s AutoDeploy Using Custom Kickstart, and Python</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2020/04/09/poor-mans-autodeploy/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>VMware Template Management using Hashicorp Packer</title>
		<link>/2020/03/23/vmware-template-packer/</link>
					<comments>/2020/03/23/vmware-template-packer/#comments</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Mon, 23 Mar 2020 13:00:00 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Packer]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=964</guid>

					<description><![CDATA[<p>VMware Templates: they make life amazing, don’t they? Initial creation of a template isn’t too hard, but there are downsides. In this article, I will talk about the downsides of traditional enterprise template management, how Packer can help, and give examples (and code!) for creating Windows and Linux templates in VMware vCenter using Packer.</p>
<p>The post <a href="/2020/03/23/vmware-template-packer/">VMware Template Management using Hashicorp Packer</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="has-text-align-left">VMware Templates: they make life amazing, don&#8217;t they? Creating a your first vSphere template is easy, but there are limitations when using them in enterprise environments. In this article, I will talk about the downsides of traditional enterprise template management, how Packer can help, and give examples (and code!) for creating Windows and Linux templates in VMware vCenter using Packer. </p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Traditional Enterprise Template Management</h2>



<ol><li>Templates Across Multiple Sites &#8211; create a master template and replicate to ensure the same state exists<ol><li>Introduces operational complexity</li><li>Extends the total amount of time it takes to patch all templates</li></ol></li><li>OS and Application updates need to be performed for every application on every template<ol><li>Repetition sucks!</li><li>Introduces risk due to <a rel="noreferrer noopener" aria-label="C2K errors (opens in a new tab)" href="https://www.lifewire.com/have-you-been-the-butt-of-a-tech-joke-2619218" target="_blank">C2K errors</a></li></ol></li><li>Template creation ends up being a work of art.<ol><li>Individuals sometimes spend years fine-tuning all of the customization in a windows template.</li><li>On-boarding time is significantly increased</li><li>Projects delivered by third parties will take extra time to complete projects, as reverse engineering will need to occur in templates</li></ol></li><li>Documentation? Do you have it for your Windows and Linux Template?</li></ol>
</div></div>



<span id="more-964"></span>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Enterprise Template Management With Packer</h2>



<ol><li>You are no longer limited to VMware! The effort used to create the template code can be used to create templates in other hypervisors, and in the cloud</li><li>Create net-new templates consistently, eliminating the old method of creating one template, and copying that to data-centers over the world.</li><li>Packer defines every configured setting and change for templates in code. Documentation: Check!</li><li>Changes to your templates make it into the wild faster and with zero configuration drift.</li></ol>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Source Code</h2>



<p>You can find source code for Windows 2019, Windows 2016, and Ubuntu 18 in my GitHub repository: <a href="https://github.com/jonhowe/Virtjunkie.com/tree/master/Packer">https://github.com/jonhowe/Virtjunkie.com/tree/master/Packer</a></p>



<p>The remainder of this post will explain how this code works.</p>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Packer Intro</h2>



<p>First and foremost, this is not a packer tutorial. Packer actually <a rel="noreferrer noopener" aria-label="provides an excellent getting started guide (opens in a new tab)" href="https://packer.io/intro/getting-started/install.html" target="_blank">provides an excellent getting started guide</a>. I&#8217;d actually recommend you start there if you have no background with packer. That said, I will blaze through a few concepts.</p>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Packer Template File &amp; User Variables</h2>



<p>Packer stores it&#8217;s configuration in JSON files and calls them Packer Templates. There are two types of files. Master packer templates, and user variable files. Both are stored in JSON. The easiest way to think of this is the master packer template file contains properties that will be used as a part of the build. The user variable file (that is specified when you actually execute the build.. more on this later) in JSON format provides the values to the properties.</p>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h3 class="wp-block-heading">Builders</h3>



<p>Hashicorp defines builders as:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow"><p><em>Builders are responsible for creating machines and generating images from them for various platforms. For example, there are separate builders for EC2, VMware, VirtualBox, etc. Packer comes with many builders by default, and can also be extended to add new builders.</em></p></blockquote>



<p>We will be using the builder called <a rel="noreferrer noopener" aria-label="VSphere-ISO (opens in a new tab)" href="https://packer.io/docs/builders/vsphere-iso.html" target="_blank">VSphere-ISO</a>.  This builder communicates directly with the vCenter API, which also makes this relevant for <a rel="noreferrer noopener" aria-label="VMC on AWS (opens in a new tab)" href="https://cloud.vmware.com/vmc-aws" target="_blank">VMC on AWS</a>.</p>
</div></div>



<h3 class="wp-block-heading">Attaching ISOs and Floppy Images</h3>



<p>Packer allows us to attach both <a rel="noreferrer noopener" aria-label="ISOs (opens in a new tab)" href="https://packer.io/docs/builders/vsphere-iso.html#iso_paths" target="_blank">ISOs</a> and <a rel="noreferrer noopener" aria-label="Floppy images (opens in a new tab)" href="https://packer.io/docs/builders/vsphere-iso.html#floppy-configuration" target="_blank">Floppy images</a> to the VM we are working with. </p>



<h4 class="wp-block-heading">ISOs</h4>



<p>You can attach multiple ISOs to an image. For example, you can attach a Windows installer ISO, as well as a VMware tools ISO to a Windows VM. Here&#8217;s an example of how this works:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">&quot;iso_paths&quot;: [
    &quot;[esxi1-nvme] ISO/Windows/14393.0.161119-1705.RS1_REFRESH_SERVER_EVAL_X64FRE_EN-US.ISO&quot;,
    &quot;[esxi1-nvme] ISO/VMTools/VMware-tools-windows-11.0.1-14773994.iso&quot;
]</pre>



<h4 class="wp-block-heading">Floppy Images</h4>



<p>Packer gives us the ability to take a file, a directory, or a floppy image, and present it to the target VM as a floppy image. This is very useful if you want to copy scripts to the VM to be executed locally. Here&#8217;s an example of how this works:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">&quot;floppy_files&quot;: [
    &quot;./autounattend.xml&quot;,
    &quot;Scripts/vmtools.cmd&quot;,
    &quot;Scripts/level0-setup.ps1&quot;
]</pre>



<h3 class="wp-block-heading">Communicators</h3>



<p><a rel="noreferrer noopener" aria-label="Communicators (opens in a new tab)" href="https://packer.io/docs/communicators/index.html" target="_blank">Communicators</a> are the mechanism Packer uses to upload files, execute scripts,  after the machine is created. Packer uses WinRM and SSH communicators. More on this later.</p>



<h3 class="wp-block-heading">Provisioners</h3>



<p>Provisioners are used to handle post image creation tasks, such as OS Customization and installing updates. Provisioners require communicators. In this case, the WinRM communicator will be used with Windows Images, while the SSH communicator will be used to communicate with Linux. We will be using the following provisioners:</p>



<figure class="wp-block-table"><table class=""><thead><tr><th class="has-text-align-left" data-align="left">Provisioner Name</th><th class="has-text-align-left" data-align="left">Used For</th></tr></thead><tbody><tr><td class="has-text-align-left" data-align="left"><a href="https://packer.io/docs/provisioners/powershell.html" target="_blank" rel="noreferrer noopener" aria-label="Powershell (opens in a new tab)">Powershell</a></td><td class="has-text-align-left" data-align="left">Performing all OS Customization Steps in Windows Images</td></tr><tr><td class="has-text-align-left" data-align="left"><a href="https://packer.io/docs/provisioners/windows-restart.html" target="_blank" rel="noreferrer noopener" aria-label="Windows-Restart (opens in a new tab)">Windows-Restart</a></td><td class="has-text-align-left" data-align="left">Restart Windows Images</td></tr><tr><td class="has-text-align-left" data-align="left"><a href="https://github.com/rgl/packer-provisioner-windows-update" target="_blank" rel="noreferrer noopener" aria-label="Windows-Update (opens in a new tab)">Windows-Update</a></td><td class="has-text-align-left" data-align="left">Apply Windows updates (community supported)</td></tr><tr><td class="has-text-align-left" data-align="left"><a href="https://packer.io/docs/provisioners/shell.html" target="_blank" rel="noreferrer noopener" aria-label="Shell (opens in a new tab)">Shell</a></td><td class="has-text-align-left" data-align="left">Used to install updates on Linux machines. We also set a custom &#8220;execution_command&#8221; that will allow for sudo to be used for all commands.</td></tr></tbody></table></figure>
</div></div>



<h2 class="wp-block-heading">Linux Templates</h2>



<p>Linux templates are pretty straight forward. Being born in open source, they are much easier to automate than Windows. Debian based distributions use a preseed file to silently execute the build. We will use packer to do the following:</p>



<ol><li>Create a blank VM</li><li>Attach Linux installer ISO</li><li>Create and attach media that has preseed.cfg file to the newly created image</li><li>Start VM</li><li>Send commands to the running VM via USB emulation to tell the Ubuntu installer to use the preseed.cfg file</li><li>Update all packages on the template</li><li>Shut Down VM</li><li>Mark as Template</li></ol>



<p>Here&#8217;s the directory structure:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">Ubuntu18/
 ├── preseed.cfg
 ├── ubuntu-18.04.json
 └── ubuntu-vars.json
 0 directories, 3 files</pre>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Windows Templates</h2>



<p>Most consumers of Packer are using it to manage Linux images, but I rarely hear about managing Windows images. Windows has a bit more moving parts that cause more complexity. It was way harder for me to figure out, even with a couple of great posts I&#8217;ll list in the reference area. In order to have a complete windows template, we will need to achieve the following steps:</p>



<ol><li>Create a blank VM</li><li>Attach Windows Installer and VMware Tools ISO</li><li>Attach floppy image that contains scripts and autounattend.xml</li><li>Start VM</li><li>Silently Install Windows Server (windowsPE pass in Autounattend.xml)</li><li>Install VMware Tools (Specialize pass in Autounattend.xml executes vmtools.cmd)</li><li>Configure WinRM (oobeSystem pass in Autounattend.xml executes level0-setup.ps1)</li><li>Perform OS Customization (Packer PowerShell provisioner executes level1-setup.ps1)</li><li>Install Windows Updates (Packer Windows Update provisioner applies updates)</li><li>Shut Down VM</li><li>Mark as Template</li></ol>



<p>Definitely more complex than Linux, eh? Don&#8217;t worry though. I&#8217;ll do my best to add some value on top of documentation and blog articles that are out there. Here&#8217;s the directory structure:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">WS19
 ├── autounattend.xml
 ├── Scripts
 │&amp;nbsp;&amp;nbsp; ├── level0-setup.ps1
 │&amp;nbsp;&amp;nbsp; ├── level1-setup.ps1
 │&amp;nbsp;&amp;nbsp; └── vmtools.cmd
 ├── vars-ws19.json
 └── ws19.json
 1 directory, 6 files</pre>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h3 class="wp-block-heading">Autounattend.xml</h3>



<p>Microsoft allows us to provide an answer file to the Windows installer to achieve a silent install of Windows Server. The installer will look in all attached media to find a file named Autounattend.xml. This file contains a number of settings that are explained in a decent amount of detail on this <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/how-configuration-passes-work" target="_blank">Microsoft documentation page</a>. Below is a high level overview of the passes and how we are using them.<br><br>I found <a rel="noreferrer noopener" aria-label="this page helpful (opens in a new tab)" href="https://www.windowsafg.com/server2016.html" target="_blank">this page helpful</a> in creating the skeleton of the XML file.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-2 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-large is-resized"><img loading="lazy" decoding="async" src="https://new.virtjunkie.com/wp-content/uploads/2020/03/dep-win8-l-configpassesandexes.jpg" alt="" class="wp-image-1005" width="610" height="341" srcset="/wp-content/uploads/2020/03/dep-win8-l-configpassesandexes.jpg 610w, /wp-content/uploads/2020/03/dep-win8-l-configpassesandexes-300x168.jpg 300w" sizes="(max-width: 610px) 100vw, 610px" /></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h4 class="wp-block-heading"><strong>windowsPE</strong></h4>



<ul><li>Select disk format</li><li>Select the OS Image (Core, GUI, Datacenter, Standard)</li><li>Add the product key (we&#8217;ll be using the 6 month trial)</li><li>Select Locale, Name, Organization</li></ul>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h4 class="wp-block-heading">offlineServicing</h4>



<ul><li>This configuration pass is used to apply updates, drivers, or language packs to a Windows image.</li></ul>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h4 class="wp-block-heading">generalize</h4>



<ul><li>We are setting the <a rel="noreferrer noopener" href="https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-security-spp-skiprearm" target="_blank">property SkipRearm</a></li><li>Resets the SID</li></ul>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h4 class="wp-block-heading">specialize</h4>



<ul><li>This configuration pass is used to create and configure information in the Windows image, and is specific to the hardware that the Windows image is installing to.</li><li>Install VMware Tools by executing (vmtools.cmd) in this step to ensure it&#8217;s available ASAP for Packer to perform the rest of template configuration steps</li><li>Computer name is set</li><li>Reboots the machine</li></ul>
</div></div>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h4 class="wp-block-heading">oobeSystem</h4>



<ul><li>Add user, set password</li><li>Execute powershell script (level0-setup.ps1) to enable WinRM, which is required for Packer provisioning</li></ul>
</div></div>
</div>
</div>
</div></div>



<h2 class="wp-block-heading">Examples</h2>



<p>Here are a few examples of how the script works</p>



<h3 class="wp-block-heading">Windows</h3>



<p>The command below will create a windows template with the following details.</p>



<figure class="wp-block-table"><table class=""><tbody><tr><td>Username</td><td>Administrator</td></tr><tr><td>Password</td><td>VMware1!</td></tr><tr><td>Additional User</td><td>Labadmin</td></tr></tbody></table></figure>



<p>If you want to change the password, you will need to specify it both in the vars file, as well as the autounattend.xml. The section you will change looks like this:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">&amp;lt;UserAccounts&gt;
    &amp;lt;AdministratorPassword&gt;
        &amp;lt;Value&gt;VMware1!&amp;lt;/Value&gt;
        &amp;lt;PlainText&gt;true&amp;lt;/PlainText&gt;
    &amp;lt;/AdministratorPassword&gt;
    &amp;lt;LocalAccounts&gt;
        &amp;lt;LocalAccount wcm:action=&quot;add&quot;&gt;
            &amp;lt;Description&gt;Lab Administrator&amp;lt;/Description&gt;
            &amp;lt;DisplayName&gt;labadmin&amp;lt;/DisplayName&gt;
            &amp;lt;Group&gt;Administrators&amp;lt;/Group&gt;
            &amp;lt;Name&gt;labadmin&amp;lt;/Name&gt;
        &amp;lt;/LocalAccount&gt;
    &amp;lt;/LocalAccounts&gt;
&amp;lt;/UserAccounts&gt;
&amp;lt;AutoLogon&gt;
    &amp;lt;Password&gt;
        &amp;lt;Value&gt;VMware1!&amp;lt;/Value&gt;
        &amp;lt;PlainText&gt;true&amp;lt;/PlainText&gt;
    &amp;lt;/Password&gt;
    &amp;lt;Enabled&gt;true&amp;lt;/Enabled&gt;
    &amp;lt;Username&gt;Administrator&amp;lt;/Username&gt;
&amp;lt;/AutoLogon&gt;</pre>



<h4 class="wp-block-heading">In Action</h4>



<pre class="urvanov-syntax-highlighter-plain-tag">packer build -var-file vars-ws19.json ws19.json
vsphere-iso: output will be in this color.

==&gt; vsphere-iso: Creating VM...
==&gt; vsphere-iso: Customizing hardware...
==&gt; vsphere-iso: Mounting ISO images...
==&gt; vsphere-iso: Creating floppy disk...
    vsphere-iso: Copying files flatly from floppy_files
    vsphere-iso: Copying file: ./autounattend.xml
    vsphere-iso: Copying file: Scripts/vmtools.cmd
    vsphere-iso: Copying file: Scripts/level0-setup.ps1
    vsphere-iso: Done copying files from floppy_files
    vsphere-iso: Collecting paths from floppy_dirs
    vsphere-iso: Resulting paths from floppy_dirs : []
    vsphere-iso: Done copying paths from floppy_dirs
==&gt; vsphere-iso: Uploading created floppy image
==&gt; vsphere-iso: Adding generated Floppy...
==&gt; vsphere-iso: Set boot order...
==&gt; vsphere-iso: Power on VM...
==&gt; vsphere-iso: Waiting for IP...
==&gt; vsphere-iso: IP address: 172.16.1.73
==&gt; vsphere-iso: Using winrm communicator to connect: 172.16.1.73
==&gt; vsphere-iso: Waiting for WinRM to become available...
    vsphere-iso: WinRM connected.
==&gt; vsphere-iso: #&amp;lt; CLIXML
==&gt; vsphere-iso: &amp;lt;Objs Version=&quot;1.1.0.1&quot; xmlns=&quot;http://schemas.microsoft.com/powershell/2004/04&quot;&gt;&amp;lt;Obj S=&quot;progress&quot; RefId=&quot;0&quot;&gt;&amp;lt;TN RefId=&quot;0&quot;&gt;&amp;lt;T&gt;System.Management.Automation.PSCustomObject&amp;lt;/T&gt;&amp;lt;T&gt;System.Object&amp;lt;/T&gt;&amp;lt;/TN&gt;&amp;lt;MS&gt;&amp;lt;I64 N=&quot;SourceId&quot;&gt;1&amp;lt;/I64&gt;&amp;lt;PR N=&quot;Record&quot;&gt;&amp;lt;AV&gt;Preparing modules for first use.&amp;lt;/AV&gt;&amp;lt;AI&gt;0&amp;lt;/AI&gt;&amp;lt;Nil /&gt;&amp;lt;PI&gt;-1&amp;lt;/PI&gt;&amp;lt;PC&gt;-1&amp;lt;/PC&gt;&amp;lt;T&gt;Completed&amp;lt;/T&gt;&amp;lt;SR&gt;-1&amp;lt;/SR&gt;&amp;lt;SD&gt; &amp;lt;/SD&gt;&amp;lt;/PR&gt;&amp;lt;/MS&gt;&amp;lt;/Obj&gt;&amp;lt;Obj S=&quot;progress&quot; RefId=&quot;1&quot;&gt;&amp;lt;TNRef RefId=&quot;0&quot; /&gt;&amp;lt;MS&gt;&amp;lt;I64 N=&quot;SourceId&quot;&gt;1&amp;lt;/I64&gt;&amp;lt;PR N=&quot;Record&quot;&gt;&amp;lt;AV&gt;Preparing modules for first use.&amp;lt;/AV&gt;&amp;lt;AI&gt;0&amp;lt;/AI&gt;&amp;lt;Nil /&gt;&amp;lt;PI&gt;-1&amp;lt;/PI&gt;&amp;lt;PC&gt;-1&amp;lt;/PC&gt;&amp;lt;T&gt;Completed&amp;lt;/T&gt;&amp;lt;SR&gt;-1&amp;lt;/SR&gt;&amp;lt;SD&gt; &amp;lt;/SD&gt;&amp;lt;/PR&gt;&amp;lt;/MS&gt;&amp;lt;/Obj&gt;&amp;lt;/Objs&gt;
==&gt; vsphere-iso: Connected to WinRM!
==&gt; vsphere-iso: Provisioning with Powershell...
==&gt; vsphere-iso: Provisioning with powershell script: Scripts/level1-setup.ps1
    vsphere-iso:
    vsphere-iso:
    vsphere-iso:     Directory: C:\Users\Administrator\Documents\WindowsPowerShell
    vsphere-iso:
    vsphere-iso:
    vsphere-iso: Mode                LastWriteTime         Length Name
    vsphere-iso: ----                -------------         ------ ----
    vsphere-iso: -a----        3/22/2020   3:02 PM              0 Microsoft.PowerShell_profile.ps1
==&gt; vsphere-iso: Restarting Machine
==&gt; vsphere-iso: Waiting for machine to restart...
==&gt; vsphere-iso: A system shutdown is in progress.(1115)
==&gt; vsphere-iso: #&amp;lt; CLIXML
    vsphere-iso: WS19-TPL restarted.
==&gt; vsphere-iso: &amp;lt;Objs Version=&quot;1.1.0.1&quot; xmlns=&quot;http://schemas.microsoft.com/powershell/2004/04&quot;&gt;&amp;lt;Obj S=&quot;progress&quot; RefId=&quot;0&quot;&gt;&amp;lt;TN RefId=&quot;0&quot;&gt;&amp;lt;T&gt;System.Management.Automation.PSCustomObject&amp;lt;/T&gt;&amp;lt;T&gt;System.Object&amp;lt;/T&gt;&amp;lt;/TN&gt;&amp;lt;MS&gt;&amp;lt;I64 N=&quot;SourceId&quot;&gt;1&amp;lt;/I64&gt;&amp;lt;PR N=&quot;Record&quot;&gt;&amp;lt;AV&gt;Preparing modules for first use.&amp;lt;/AV&gt;&amp;lt;AI&gt;0&amp;lt;/AI&gt;&amp;lt;Nil /&gt;&amp;lt;PI&gt;-1&amp;lt;/PI&gt;&amp;lt;PC&gt;-1&amp;lt;/PC&gt;&amp;lt;T&gt;Completed&amp;lt;/T&gt;&amp;lt;SR&gt;-1&amp;lt;/SR&gt;&amp;lt;SD&gt; &amp;lt;/SD&gt;&amp;lt;/PR&gt;&amp;lt;/MS&gt;&amp;lt;/Obj&gt;&amp;lt;Obj S=&quot;progress&quot; RefId=&quot;1&quot;&gt;&amp;lt;TNRef RefId=&quot;0&quot; /&gt;&amp;lt;MS&gt;&amp;lt;I64 N=&quot;SourceId&quot;&gt;2&amp;lt;/I64&gt;&amp;lt;PR N=&quot;Record&quot;&gt;&amp;lt;AV&gt;Preparing modules for first use.&amp;lt;/AV&gt;&amp;lt;AI&gt;0&amp;lt;/AI&gt;&amp;lt;Nil /&gt;&amp;lt;PI&gt;-1&amp;lt;/PI&gt;&amp;lt;PC&gt;-1&amp;lt;/PC&gt;&amp;lt;T&gt;Completed&amp;lt;/T&gt;&amp;lt;SR&gt;-1&amp;lt;/SR&gt;&amp;lt;SD&gt; &amp;lt;/SD&gt;&amp;lt;/PR&gt;&amp;lt;/MS&gt;&amp;lt;/Obj&gt;&amp;lt;/Objs&gt;
==&gt; vsphere-iso: Machine successfully restarted, moving on
==&gt; vsphere-iso: Uploading the Windows update elevated script...
==&gt; vsphere-iso: Uploading the Windows update check for reboot required elevated script...
==&gt; vsphere-iso: Uploading the Windows update script...
==&gt; vsphere-iso: Running Windows update...
    vsphere-iso: Searching for Windows updates...
    vsphere-iso: Found Windows update (2018-10-15; 20.72 MB): Update for Adobe Flash Player for Windows Server 2019 (1809) for x64-based Systems (KB4462930)
    vsphere-iso: Found Windows update (2020-02-11; 20.75 MB): 2020-02 Security Update for Adobe Flash Player for Windows Server 2019 for x64-based Systems (KB4537759)
    vsphere-iso: Found Windows update (2020-02-25; 71.37 MB): 2020-02 Cumulative Update for .NET Framework 3.5, 4.7.2 and 4.8 for Windows Server 2019 for x64 (KB4538156)
    vsphere-iso: Found Windows update (2020-02-25; 2.34 MB): 2020-01 Update for Windows Server 2019 for x64-based Systems (KB4494174)
    vsphere-iso: Found Windows update (2020-03-10; 30.62 MB): Windows Malicious Software Removal Tool x64 - March 2020 (KB890830)
    vsphere-iso: Found Windows update (2020-03-22; 114.85 MB): Security Intelligence Update for Windows Defender Antivirus - KB2267602 (Version 1.311.1752.0)
    vsphere-iso: Found Windows update (2020-03-10; 15349.68 MB): 2020-03 Cumulative Update for Windows Server 2019 (1809) for x64-based Systems (KB4538461)
    vsphere-iso: Downloading Windows updates (7 updates; 15610.33 MB)...
    vsphere-iso: Waiting for operation to complete (system performance: 44% cpu; 31% memory)...
    vsphere-iso: Installing Windows updates...
    vsphere-iso: Waiting for operation to complete (system performance: 20% cpu; 41% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 51% cpu; 51% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 51% cpu; 50% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 50% cpu; 54% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 43% cpu; 55% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 0% cpu; 61% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 38% cpu; 52% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 63% cpu; 48% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 27% cpu; 46% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 45% cpu; 47% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 55% cpu; 46% memory)...
    vsphere-iso: Waiting for operation to complete (system performance: 53% cpu; 44% memory)...
    vsphere-iso: Waiting for the Windows Modules Installer to exit...
    vsphere-iso: Waiting for operation to complete (system performance: 81% cpu; 44% memory)...
==&gt; vsphere-iso: Restarting the machine...
==&gt; vsphere-iso: Waiting for machine to become available...
==&gt; vsphere-iso: A system shutdown is in progress.(1115)
==&gt; vsphere-iso: A system shutdown is in progress.(1115)
    vsphere-iso: Waiting for the Windows Modules Installer to exit...
    vsphere-iso: WS19-TPL restarted.
==&gt; vsphere-iso: Running Windows update...
    vsphere-iso: Searching for Windows updates...
    vsphere-iso: Found Windows update (2020-03-19; 4.91 MB): Update for Windows Defender Antivirus antimalware platform - KB4052623 (Version 4.18.2003.6)
    vsphere-iso: Downloading Windows updates (1 updates; 4.91 MB)...
    vsphere-iso: Installing Windows updates...
==&gt; vsphere-iso: Shut down VM...
==&gt; vsphere-iso: Deleting Floppy drives...
==&gt; vsphere-iso: Deleting Floppy image...
==&gt; vsphere-iso: Eject CD-ROM drives...
==&gt; vsphere-iso: Convert VM into template...
Build 'vsphere-iso' finished.

==&gt; Builds finished. The artifacts of successful builds are:
--&gt; vsphere-iso: WS19-TPL</pre>



<h3 class="wp-block-heading">Linux</h3>



<p>The command below will create a Ubuntu template with the following details:</p>



<figure class="wp-block-table"><table class=""><tbody><tr><td>Root Password</td><td>VMware1!</td></tr><tr><td>Additional Username (also added to sudoers)</td><td>jhowe</td></tr><tr><td>Additional username&#8217;s password</td><td>VMware1!</td></tr></tbody></table></figure>



<p>All of the above can be changed by modifying values in the preseed.cfg file.</p>



<h4 class="wp-block-heading">In Action</h4>



<pre class="urvanov-syntax-highlighter-plain-tag">packer build -var-file ubuntu-vars.json ubuntu-18.04.json

jhowe@jonlaptopalt:~/git/Personal/HomeLab/packer/Ubuntu18$ packer build -var-file ubuntu-vars.json ubuntu-18.04.json 
vsphere-iso: output will be in this color.

==&gt; vsphere-iso: Creating VM...
==&gt; vsphere-iso: Customizing hardware...
==&gt; vsphere-iso: Mounting ISO images...
==&gt; vsphere-iso: Creating floppy disk...
    vsphere-iso: Copying files flatly from floppy_files
    vsphere-iso: Copying file: ./preseed.cfg
    vsphere-iso: Done copying files from floppy_files
    vsphere-iso: Collecting paths from floppy_dirs
    vsphere-iso: Resulting paths from floppy_dirs : []
    vsphere-iso: Done copying paths from floppy_dirs
==&gt; vsphere-iso: Uploading created floppy image
==&gt; vsphere-iso: Adding generated Floppy...
==&gt; vsphere-iso: Set boot order...
==&gt; vsphere-iso: Power on VM...
==&gt; vsphere-iso: Waiting 10s for boot...
==&gt; vsphere-iso: Typing boot command...
==&gt; vsphere-iso: Waiting for IP...
==&gt; vsphere-iso: IP address: 172.16.1.72
==&gt; vsphere-iso: Using ssh communicator to connect: 172.16.1.72
==&gt; vsphere-iso: Waiting for SSH to become available...
==&gt; vsphere-iso: Connected to SSH!
==&gt; vsphere-iso: Provisioning with shell script: /tmp/packer-shell338854810
    vsphere-iso: Hit:1 http://security.ubuntu.com/ubuntu bionic-security InRelease
    vsphere-iso: Hit:2 http://us.archive.ubuntu.com/ubuntu bionic InRelease
    vsphere-iso: Hit:3 http://us.archive.ubuntu.com/ubuntu bionic-updates InRelease
    vsphere-iso: Hit:4 http://us.archive.ubuntu.com/ubuntu bionic-backports InRelease
    vsphere-iso: Reading package lists...
    vsphere-iso: Reading package lists...
    vsphere-iso: Building dependency tree...
    vsphere-iso: Reading state information...
    vsphere-iso: Calculating upgrade...
    vsphere-iso: The following packages have been kept back:
    vsphere-iso:   linux-generic linux-headers-generic linux-image-generic
    vsphere-iso: The following packages will be upgraded:
    vsphere-iso:   dmidecode gcc-8-base libdrm-common libdrm2 libgcc1 libicu60 libnss-systemd
    vsphere-iso:   libpam-systemd libsqlite3-0 libstdc++6 libsystemd0 libudev1 libxml2
    vsphere-iso:   linux-firmware rsync systemd systemd-sysv udev
    vsphere-iso: 18 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
    vsphere-iso: Need to get 89.7 MB of archives.
    vsphere-iso: After this operation, 572 kB of additional disk space will be used.
    vsphere-iso: Get:1 http://us.archive.ubuntu.com/ubuntu bionic-updates/main amd64 perl-modules-5.26 all 5.26.1-6ubuntu0.3 [2,763 kB]

[Omitted some output in order to save space. Apt is downloading new packages]

[Omitted some output in order to save space. Apt is unpacking packages]

[Omitted some output in order to save space. Apt is &quot;Setting up... all upgraded packages]

    vsphere-iso: Processing triggers for systemd (237-3ubuntu10.39) ...
    vsphere-iso: Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
    vsphere-iso: Processing triggers for dbus (1.12.2-1ubuntu1.1) ...
    vsphere-iso: Processing triggers for mime-support (3.60ubuntu1) ...
    vsphere-iso: Processing triggers for ureadahead (0.100.0-21) ...
    vsphere-iso: Processing triggers for install-info (6.5.0.dfsg.1-2) ...
    vsphere-iso: Processing triggers for libc-bin (2.27-3ubuntu1) ...
    vsphere-iso: Template Build Complete
==&gt; vsphere-iso: Shut down VM...
==&gt; vsphere-iso: Deleting Floppy drives...
==&gt; vsphere-iso: Deleting Floppy image...
==&gt; vsphere-iso: Eject CD-ROM drives...
==&gt; vsphere-iso: Convert VM into template...
Build 'vsphere-iso' finished.

==&gt; Builds finished. The artifacts of successful builds are:
--&gt; vsphere-iso: Ubuntu18</pre>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">References</h2>



<p>I did a lot of research as when getting this up and running. The following sites were helpful.</p>



<ul><li>This is an EXCELLENT blog. The article he created unfortunately didn&#8217;t work, but it got me started. Either way, it&#8217;s worth a look. (<a href="https://dteslya.engineer/automation/2018-12-20-creating_vm_templates_with_packer/">https://dteslya.engineer/automation/2018-12-20-creating_vm_templates_with_packer/</a>)</li><li>Official Packer Documentation (<a href="https://packer.io/docs/index.html">https://packer.io/docs/index.html</a>)</li></ul>
</div></div>
<p>The post <a href="/2020/03/23/vmware-template-packer/">VMware Template Management using Hashicorp Packer</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2020/03/23/vmware-template-packer/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Deploy VCSA via PowerShell</title>
		<link>/2020/03/16/deploy-vcsa-via-powershell/</link>
					<comments>/2020/03/16/deploy-vcsa-via-powershell/#comments</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Mon, 16 Mar 2020 13:00:00 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=866</guid>

					<description><![CDATA[<p>I've been spending a lot of time lately thinking about how organizations can provide services can operationalize the principles behind Infrastructure as Code in a way that's accessible. In my experience, if a tool isn't easy to use, it won't be used. This is one of the biggest barriers to organizations (and companies that provide services, like mine) benefiting from IaC. It's my intention that this script will achieve a high level of usability and will also generate and consume reusable code for future use.</p>
<p>The post <a href="/2020/03/16/deploy-vcsa-via-powershell/">Deploy VCSA via PowerShell</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image is-style-default"><figure class="alignleft size-large is-resized"><img loading="lazy" decoding="async" src="https://new.virtjunkie.com/wp-content/uploads/2014/04/powercli-icon.jpg" alt="" class="wp-image-585" width="101" height="101"/></figure></div>



<p>I&#8217;ve been spending a lot of time lately thinking about how organizations can provide services can operationalize the principles behind Infrastructure as Code in a way that&#8217;s accessible. In my experience, if a tool isn&#8217;t easy to use, it won&#8217;t be used. This is one of the biggest barriers to organizations (and companies that provide services, like mine) benefiting from IaC. It&#8217;s my intention that this script will achieve a high level of usability and will also generate and consume reusable code for future use.</p>



<span id="more-866"></span>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="has-text-align-center wp-block-heading">Recap</h2>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-3 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h3 class="wp-block-heading">Challenge</h3>



<p>You want to use Infrastructure as Code principles to deploy your vCenter Server, but you want to ensure that your solution is accessible without code as well.</p>
</div></div>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group" id="Solution"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h3 class="wp-block-heading">Solution</h3>



<p>Create a script that gathers all relevant information for a VCSA deployment via the the <a rel="noreferrer noopener" href="https://docs.vmware.com/en/VMware-vSphere/6.7/com.vmware.vcenter.install.doc/GUID-4CCC26AB-D2E4-40D0-97A8-804FB6274009.html" target="_blank">vcsa-deploy</a> and generates the JSON file that the utility consumes, while also allowing for the download of the VCSA ISO from a web server.</p>
</div></div>
</div>
</div>
</div></div>



<div class="wp-block-group" id="Background"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Background</h2>



<p>In order for this to fit my definition of infrastructure as code, we should be able to define all details of the vCenter in a structured format. Additionally, we should not assume that the vCenter installer is local, and should pull it from an external location if we need it to. While the vcsa-deploy utility can handle the installation of the vCenter, I&#8217;ve found most people don&#8217;t like it. </p>



<p>With this script, I allow a VI  admin to fill out all relevant details of the vCenter in a spreadsheet. The script will then access the spreadsheet directly, and generate the JSON file used by vcsa-deploy. As a bonus, it will call the vcsa-deploy utility and kick off the actual deployment.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="233" src="https://www.virtjunkie.com/wp-content/uploads/2020/03/2020-03-15_12-07-1024x233.png" alt="" class="wp-image-872" srcset="/wp-content/uploads/2020/03/2020-03-15_12-07-1024x233.png 1024w, /wp-content/uploads/2020/03/2020-03-15_12-07-300x68.png 300w, /wp-content/uploads/2020/03/2020-03-15_12-07-768x175.png 768w, /wp-content/uploads/2020/03/2020-03-15_12-07.png 1160w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption>Screenshot of the excel file <a rel="noreferrer noopener" href="https://github.com/jonhowe/Virtjunkie.com/tree/master/VCSA-AutoDeploy" target="_blank">on my GitHub account</a>.</figcaption></figure>
</div></div>



<div class="wp-block-group" id="Demo"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Demo</h2>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="726" src="https://www.virtjunkie.com/wp-content/uploads/2020/03/image-1024x726.png" alt="" class="wp-image-944" srcset="/wp-content/uploads/2020/03/image-1024x726.png 1024w, /wp-content/uploads/2020/03/image-300x213.png 300w, /wp-content/uploads/2020/03/image-768x544.png 768w, /wp-content/uploads/2020/03/image.png 1043w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption>Quick demo &#8211; the installer up to where it deploys the VCSA</figcaption></figure>
</div></div>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-4 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group" id="Features"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Features</h2>



<ul><li>Validate Password Complexity</li><li>Provide Input via Excel Spreadsheet or JSON file</li><li>Download ISO, extract contents</li><li>Deploy vCenter to either ESXi or vCenter</li></ul>
</div></div>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<div class="wp-block-group" id="Requirements"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Requirements</h2>



<ul><li><a rel="noreferrer noopener" href="https://github.com/dfinke/ImportExcel" target="_blank">ImportExcel module</a></li><li>7-zip</li><li>URL to a vCenter Server 6.7 Appliance ISO</li><li>Standard vCenter Prerequisites (forward/reverse DNS, space, networking, etc) (<a rel="noreferrer noopener" aria-label="link (opens in a new tab)" href="https://docs.vmware.com/en/VMware-vSphere/6.7/com.vmware.vcenter.upgrade.doc/GUID-752FCA83-1A9B-499E-9C65-D5625351C0B5.html" target="_blank">link</a>)</li></ul>
</div></div>
</div>
</div>



<div class="wp-block-group" id="Code-Review"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Code Review</h2>



<p>The code can be located on my <a rel="noreferrer noopener" aria-label="github account (opens in a new tab)" href="https://github.com/jonhowe/Virtjunkie.com/tree/master/VCSA-AutoDeploy" target="_blank">github account</a>. As per usual, let&#8217;s go through the code.<br><br><strong>Lines 1-31</strong><br>Documentation<br><br><strong>Lines 32-58</strong><br>Define parameters<br><br><strong>Lines 66-91</strong><br>Download and install the ISO<br><br><strong>Lines</strong> <strong>93-130</strong><br>Extract the ISO using 7-zip<br><br><strong>Lines 133-139</strong><br>Use import-excel to grab sections of the spreadsheet. There&#8217;s a bit of overhead, but my goal here was for the spreadsheet to look good.<br><br><strong>Lines 141-152</strong><br>Validate the password specified meets VMware&#8217;s requirements for the VCSA<br><br><strong>Lines 154-172</strong><br>Detect the OS<br><br><strong>Lines 176-224</strong><br>Determine whether we are deploying to a vCenter or an ESXi host and create the respective JSON. This is the only difference between deploying to a vCenter or an ESXi host.<br><br><strong>Lines 226-298</strong><br>Create a hashtable used for to create the rest of parameters common to a the json used by vcsa-deploy.<br><br><strong>Lines 300-312</strong><br>Write the JSON file to disk<br><br><strong>Lines 314-333</strong><br>Begin the install<br><br><strong>Lines 335-343</strong><br>Determine if the install was successful. If it failed, print out the error messages.</p>
</div></div>



<div class="wp-block-group" id="Code"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">Code</h2>



<pre class="urvanov-syntax-highlighter-plain-tag">#Github: https://github.com/jonhowe/Virtjunkie.com/tree/master/VCSA-AutoDeploy
#Blog Post: http://www.virtjunkie.com/deploy-vcsa-via-powershell/

&amp;lt;#
.SYNOPSIS
Install the VMware vCenter Server Appliance based on input from a Microsoft Excel File

.DESCRIPTION
This script will install the VMware vCenter Server Appliance based on input from a Microsoft Excel File.

.PARAMETER ForceDownload
Switch parameter that will force a (re) download and extract of the ISO

.PARAMETER URI
This is the URL of the vCenter Installer ISO

.PARAMETER Workspace
Absolute path to the directory that will be used as a workspace. The vCenter ISO will be downloaded there, and will be
extracted there as well.

.PARAMETER DeploymentTarget
Location that the new VCSA will be deployed to.
Valid options are: ESXi, vCenter

.PARAMETER ExcelFile
Absolute path to the Excel file that contains the parameters required for vCenter to be built

.PARAMETER 7z
Absolute path path to the 7z binary
#&gt;
#Requires -modules Microsoft.powershell.archive,importexcel
[CmdletBinding()]
param (
    [switch]$ForceDownload
    ,
    $URI = &quot;http://jondesktop.home.lan:8123/files/VMware/VSMRepo/dlg_VC67U3B/VMware-VCSA-all-6.7.0-15132721.iso&quot;
    ,
    [Parameter(Mandatory=$true)]
    [ValidateScript( {
            if ( -Not ($_ | Test-Path) ) {
                throw &quot;File or folder does not exist&quot;
            }
            return $true
        })]
    $Workspace
    ,
    [validateset(&quot;vCenter&quot;, &quot;ESXi&quot;)]
    $deploymentTarget
    ,
    [ValidateScript( { Test-Path $_ })]
    [string]
    $ExcelFile = &quot;/home/jhowe/git/Personal/AutomatedLab/JonAutoLab/HostDetails.xlsx&quot;
    ,
    [Parameter(Mandatory=$true)]
    [ValidateScript( { Test-Path $_ })]
    [string]
    $7z = '/usr/bin/7z'
)
$ErrorActionPreference = 'Stop'

#region Download and Extract the ISO
$VCSA_Installer_Archive = $workspace + ($uri.Split('/')[-1])
$VCSA_Extracted_Directory = ($VCSA_Installer_Archive.Split(&quot;.iso&quot;)[0])
$VCSA_CLI_Installer_Path = ($VCSA_Extracted_Directory + &quot;/vcsa-cli-installer/&quot;)

#Download the VCSA only if it doesn't already exist
if ((Test-Path $VCSA_Installer_Archive) -eq $false -or $forcedownload) {
    $filesize = (Invoke-WebRequest $uri -Method Head).Headers.'Content-Length'
    [int]$WebServerFileSize = ([convert]::ToInt64($filesize, 10)) / 1024

    Write-Output &quot;Downloading VCSA Installer&quot;
    $wc = New-Object System.Net.WebClient
    $wc.DownloadFileAsync($uri, $VCSA_Installer_Archive)

    #The following loop will print the progressof the download every 15 seconds
    $incomplete = $true
    while ($incomplete) {
        $CurrentSize = ((Get-Item $VCSA_Installer_Archive).length) / 1024
    
        if ($CurrentSize -eq $WebServerFileSize) {
            $incomplete = $false
        }
        else {
            Write-Output &quot;File Download Size is $([math]::round($CurrentSize,0)) / $($WebServerFileSize) ($(($CurrentSize / $WebServerFileSize).ToString(&quot;P&quot;) )%)&quot;
            Start-Sleep -Seconds 15
        }
    }
}
else {
    Write-Output &quot;VCSA Installer already exists&quot;    
}

#Extract the VCSA only if the directory it should be extracted to doesn't already exist
if ((Test-Path ($VCSA_Extracted_Directory)) -eq $false -or $forcedownload) {
    Write-Output &quot;Unzipping VCSA&quot;
    #Expand-Archive -LiteralPath $VCSA_Installer_Archive -destinationpath $workspace

    Write-Output &quot;Extracting the ISO now...&quot;
    $arguments = &quot;x -bb0 -bd -y -o$($VCSA_Extracted_Directory) $($VCSA_Installer_Archive)&quot;
    Write-Verbose -Message ($7z + &quot; &quot; + $arguments)

    $pinfo = New-Object System.Diagnostics.ProcessStartInfo
    $pinfo.FileName = $7z
    $pinfo.RedirectStandardError = $true
    $pinfo.RedirectStandardOutput = $true
    $pinfo.UseShellExecute = $false
    $pinfo.Arguments = $arguments
    $p = New-Object System.Diagnostics.Process
    $p.StartInfo = $pinfo
    $p.Start() | Out-Null
    $p.WaitForExit()
    $7z_stdout = $p.StandardOutput.ReadToEnd()
    $7z_stderr = $p.StandardError.ReadToEnd()

    $7z_stdout | out-file -Path ($workspace + &quot;7z-stdout.txt&quot;)
    $7z_stderr | out-file -Path ($workspace + &quot;7z-stderr.txt&quot;)

    if ($p.ExitCode -ne 0) {
        Write-Output &quot;There was an error...&quot;
        Write-Output &quot;Process finished with exit code $($p.ExitCode)&quot;
        Write-Output &quot;Log data written to: $($workspace)7z-stdout.txt and $($workspace)7z-stderr.txt&quot;
        $7z_stderr
    }
    else {
        Write-Output &quot;Extraction completed successfully.&quot;
    }
}
else {
    Write-Output &quot;VCSA has already been unzipped&quot;
}
#endregion Download and Extract the ISO

#region import excel file into sections and validate input
$targettype = Import-Excel $excelfile -WorksheetName vCenter -StartRow 1 -EndRow 2 -StartColumn 1 -EndColumn 1
$targetinfo = Import-Excel $excelfile -WorksheetName vCenter -StartRow 1 -EndRow 2 -StartColumn 2 -EndColumn 8
$applianceinfo = Import-Excel $excelfile  -WorksheetName vCenter -StartRow 4 -EndRow 5 -StartColumn 1 -EndColumn 3
$networkinfo = Import-Excel $excelfile  -WorksheetName vCenter -StartRow 7 -EndRow 8 -StartColumn 1 -EndColumn 7
$os = Import-Excel $excelfile  -WorksheetName vCenter -StartRow 10 -EndRow 11 -StartColumn 1 -EndColumn 3 
$sso_ciep = Import-Excel $excelfile  -WorksheetName vCenter -StartRow 13 -EndRow 14 -StartColumn 1 -EndColumn 3

#Ensure the password specified has the appropriate complexity based on vCenter's requirements
$input = ($os.&quot;vCenter Root Password&quot;)
if (($input -cmatch '[a-z]') `
        -and ($input -match '\d') `
        -and ($input.length -ge 8) `
        -and ($input -match '!|@|#|%|^|&amp;amp;|$')) {
    Write-Output &quot;Password complexity is sufficient. Continuing.&quot;
}
else {
    Write-Output &quot;$input does not meet complexity requirements. Password must be at least 8 characters, include one numeric, and one special character.&quot;
    exit
}

$deploymentTarget = $targettype.'vCenter or ESXi'

#endregion import excel file into sections and validate input

#region Detect the OS (Windows, Linux, OSX)
if ($IsWindows -or $ENV:OS) {
    $installer_dir = ($VCSA_CLI_Installer_Path + &quot;win32/&quot;)
    $installer = ($installer_dir + &quot;vcsa-deploy.exe&quot;)
} 
elseif ($IsLinux) {
    $installer_dir = ($VCSA_CLI_Installer_Path + &quot;lin64/&quot;)
    $installer = ($installer_dir + &quot;vcsa-deploy&quot;)
    chmod -R +x $workspace
}
elseif ($IsMacOS) {
    $installer_dir = ($VCSA_CLI_Installer_Path + &quot;mac/&quot;)
    $installer = ($installer_dir + &quot;vcsa-deploy&quot;)
}
#endregion Detect the OS (Windows, Linux, OSX)

#region Create and format the JSON

#Detect whether we are deploying to vCenter or ESXi
switch ($deploymentTarget) {
    'vCenter' {
        Write-Output &quot;Deploying to vCenter&quot;
        $target = [ordered] @{
            vc = [ordered]@{
                __comments         = @(&quot;'datacenter' must end with a datacenter name, and only with a datacenter name. &quot;,
                    &quot;'target' must end with an ESXi hostname, a cluster name, or a resource pool name. &quot;,
                    &quot;The item 'Resources' must precede the resource pool name. &quot;,
                    &quot;All names are case-sensitive. &quot;,
                    &quot;For details and examples, refer to template help, i.e. vcsa-deploy {install|upgrade|migrate} --template-help&quot;)
                hostname           = $targetinfo.&quot;Target Host or vCenter&quot;
                username           = $targetinfo.&quot;Username&quot;
                password           = $targetinfo.&quot;Password&quot;
                deployment_network = $targetinfo.&quot;PortGroup&quot;

                &amp;lt;#
                datacenter         = @(&quot;Folder 1 (parent of Folder 2)&quot;,
                                        &quot;Folder 2 (parent of Your Datacenter)&quot;,
                                        &quot;Your Datacenter&quot;)
                #&gt;
                datacenter         = $targetinfo.&quot;Datacenter (vCenter Only)&quot;
                datastore          = $targetinfo.&quot;Datastore&quot;
                &amp;lt;#
                target             = @( &quot;Folder A (parent of Folder B)&quot;,
                                        &quot;Folder B (parent of Your ESXi Host, or Cluster)&quot;,
                                        &quot;Your ESXi Host, or Cluster&quot;)
                #&gt;
                target             = $targetinfo.&quot;Cluster Name (vCenter Only)&quot;
            }
        }
    }
    'ESXi' {
        Write-Output &quot;Deploying to ESXi&quot;
        $target = [ordered] @{
            esxi = [ordered]@{
                hostname           = $targetinfo.&quot;Target Host or vCenter&quot;
                username           = $targetinfo.&quot;Username&quot;
                password           = $targetinfo.&quot;Password&quot;
                deployment_network = $targetinfo.&quot;PortGroup&quot;
                datastore          = $targetinfo.&quot;Datastore&quot;
            }
        }
    }
    Default {
        Write-Error &quot;Invalid Deployment Target Specified. Exiting.&quot;
        exit
    }
}

&amp;lt;#
I'm aware that others have imported the json file provided by the installer...
I don't have a great reason that I didn't do that.. maybe I'm just different :-)
Either way - we are simply generating a hashtable here, and then writing it to a file.
#&gt;
$common_properties = @{
    appliance = [ordered]@{
        __comments        = @(&quot;You must provide the 'deployment_option' key with a value, which will affect the VCSA's configuration parameters, such as the VCSA's number of vCPUs, the memory size, the storage size, and the maximum numbers of ESXi hosts and VMs which can be managed. For a list of acceptable values, run the supported deployment sizes help, i.e. vcsa-deploy --supported-deployment-sizes&quot;)
        thin_disk_mode    = $applianceinfo.&quot;Thin Disk?&quot;
        deployment_option = $applianceinfo.&quot;vCenter Size&quot;
        name              = $applianceinfo.&quot;VM Name&quot;
    }
    network   = [ordered]@{
        ip_family   = $networkinfo.&quot;IP v4 or v6&quot;
        mode        = $networkinfo.&quot;IP Allocation Mode&quot;
        ip          = $networkinfo.&quot;IP Address&quot;
        dns_servers = @($networkinfo.'DNS Server List').split(&quot;,&quot;)
        prefix      = ($networkinfo.&quot;CIDR Block&quot;).tostring()
        gateway     = $networkinfo.&quot;Default Gateway&quot;
        system_name = $networkinfo.&quot;vCenter Hostname&quot;
    }
    os        = [ordered]@{
        password    = $os.&quot;vCenter Root Password&quot;
        ntp_servers = $os.&quot;NTP Servers&quot;
        ssh_enable  = $os.&quot;Enable SSH By Default?&quot;
    }
    sso       = [ordered]@{
        password    = $sso_ciep.&quot;SSO Password&quot;
        domain_name = $sso_ciep.&quot;SSO Domain Name&quot;
    }
}

$combined = [ordered]@{
    __version  = &quot;2.13.0&quot;
    __comments = &quot;Sample template to deploy a vCenter Server Appliance with an embedded Platform Services Controller on an ESXi host.&quot;
    new_vcsa   = $target + $common_properties
    ceip       = [ordered]@{
        description = @{
            __comments = @(&quot;++++VMware Customer Experience Improvement Program (CEIP)++++&quot;,
                &quot;VMware's Customer Experience Improvement Program (CEIP) &quot;,
                &quot;provides VMware with information that enables VMware to &quot;,
                &quot;improve its products and services, to fix problems, &quot;,
                &quot;and to advise you on how best to deploy and use our &quot;,
                &quot;products. As part of CEIP, VMware collects technical &quot;,
                &quot;information about your organization's use of VMware &quot;,
                &quot;products and services on a regular basis in association &quot;,
                &quot;with your organization's VMware license key(s). This &quot;,
                &quot;information does not personally identify any individual. &quot;,
                &quot;&quot;,
                &quot;Additional information regarding the data collected &quot;,
                &quot;through CEIP and the purposes for which it is used by &quot;,
                &quot;VMware is set forth in the Trust &amp;amp; Assurance Center at &quot;,
                &quot;http://www.vmware.com/trustvmware/ceip.html . If you &quot;,
                &quot;prefer not to participate in VMware's CEIP for this &quot;,
                &quot;product, you should disable CEIP by setting &quot;,
                &quot;'ceip_enabled': false. You may join or leave VMware's &quot;,
                &quot;CEIP for this product at any time. Please confirm your &quot;,
                &quot;acknowledgement by passing in the parameter &quot;,
                &quot;--acknowledge-ceip in the command line.&quot;,
                &quot;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++&quot;)       
        }
        
        settings    = @{ 
            #TODO I believe an extra member is needed if this is enabled
            ceip_enabled = $sso_ciep.&quot;Enable CIEP?&quot;
        }
    }
}

$json = $combined | ConvertTo-Json -Depth 99
$fixtrue = $json.replace(&quot;`&quot;true`&quot;&quot;, &quot;true&quot;)
$FinalJSON = $fixtrue.replace(&quot;`&quot;false`&quot;&quot;, &quot;false&quot;)
#endregion Create and format the JSON

#region Write the json file to disk
switch ($deploymentTarget) {
    'vCenter' {  
        $FinalConfigFile = $workspace + &quot;$(($FinalJSON | convertfrom-json).new_vcsa.vc.hostname).json&quot;
    }
    'ESXi' {  
        $FinalConfigFile = $workspace + &quot;$(($FinalJSON | convertfrom-json).new_vcsa.esxi.hostname).json&quot;
    }
    Default { }
}
$FinalJSON | out-file -FilePath $FinalConfigFile
Write-Output (&quot;JSON file written to: &quot; + $FinalConfigFile)
#endregion Write the json file to disk

#region Start the install
Write-Output &quot;Beginning install now.. this will take a few minutes. Please wait.&quot;
$arguments = &quot;install --accept-eula --no-ssl-certificate-verification --log-dir $($VCSA_CLI_Installer_Path) $($FinalConfigFile)&quot;

$pinfo = New-Object System.Diagnostics.ProcessStartInfo
$pinfo.FileName = $installer
$pinfo.RedirectStandardError = $true
$pinfo.RedirectStandardOutput = $true
$pinfo.UseShellExecute = $false
$pinfo.Arguments = $arguments
$p = New-Object System.Diagnostics.Process
$p.StartInfo = $pinfo
$p.Start() | Out-Null
$p.WaitForExit()
$stdout = $p.StandardOutput.ReadToEnd()
$stderr = $p.StandardError.ReadToEnd()

$stdout | out-file -Path ($VCSA_CLI_Installer_Path + &quot;stdout.txt&quot;)
$stderr | out-file -Path ($VCSA_CLI_Installer_Path + &quot;stderr.txt&quot;)
#endregion Start the install

if ($p.ExitCode -ne 0) {
    Write-Output &quot;There was an error...&quot;
    Write-Output &quot;Process finished with exit code $($p.ExitCode)&quot;
    Write-Output &quot;Log data written to: $($VCSA_CLI_Installer_Path)stdout.txt and $($VCSA_CLI_Installer_Path)stderr.txt&quot;
    $stderr
}
else {
    Write-Output &quot;Install completed successfully.&quot;
}</pre>
</div></div>



<div class="wp-block-group" id="WhatsNext"><div class="wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow">
<h2 class="wp-block-heading">What&#8217;s next?</h2>



<p>Good question! vSphere 7 is releasing vCenter Server Profiles and Image Cluster Management.  Creating tools that can consume these new features will be helpful.<br><br>I&#8217;m working on template management using <a rel="noreferrer noopener" aria-label="packer (opens in a new tab)" href="https://packer.io/" target="_blank">Hashicorp&#8217;s Packer</a> and will be posting some of my work on that soon. In addition, I have done some work on <a rel="noreferrer noopener" aria-label="Hashicorp's Terraform (opens in a new tab)" href="https://www.terraform.io/" target="_blank">Hashicorp&#8217;s Terraform</a> for deploying lab VMs that I&#8217;ll share too. Finally &#8211; I&#8217;ve got a few skeleton <a rel="noreferrer noopener" aria-label="Ansible Playbooks (opens in a new tab)" href="https://www.ansible.com/" target="_blank">Ansible Playbooks</a> that I&#8217;m working on for configuration of the lab VMs, as well as a playbook for doing high level configuration of a bare vCenter. So in short &#8211; lots more coming!</p>
</div></div>



<p>Thanks for viewing,<br>Jon</p>
<p>The post <a href="/2020/03/16/deploy-vcsa-via-powershell/">Deploy VCSA via PowerShell</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2020/03/16/deploy-vcsa-via-powershell/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>Validate Network Connectivity Across A VMware Cluster</title>
		<link>/2019/10/21/vsphere-test-cluster-connectivity/</link>
					<comments>/2019/10/21/vsphere-test-cluster-connectivity/#respond</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Mon, 21 Oct 2019 23:45:26 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=818</guid>

					<description><![CDATA[<p>It&#8217;s the network team&#8217;s fault&#8230; The Scenario Imagine you have an environment that has hundreds of VLANs. When you build a new cluster, there&#8217;s a real possibility that one host out of many is mis-configured on just a single port group or VLAN. It&#8217;s a pretty simple issue, but it&#8217;s like finding a needle in [&#8230;]</p>
<p>The post <a href="/2019/10/21/vsphere-test-cluster-connectivity/">Validate Network Connectivity Across A VMware Cluster</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<blockquote class="wp-block-quote is-style-large is-layout-flow wp-block-quote-is-layout-flow"><p>It&#8217;s the network team&#8217;s fault&#8230;</p></blockquote>



<h2 class="wp-block-heading">The  Scenario</h2>



<p>Imagine you have an environment that has hundreds of VLANs. When you build a new cluster, there&#8217;s a real possibility that one host out of many is mis-configured on just a single port group or VLAN. It&#8217;s a pretty simple issue, but it&#8217;s like finding a needle in a haystack. Because of that, it&#8217;s incredibly difficult to troubleshoot, so I wrote a script to run through every ESXi host, and test connectivity on each port group.</p>



<span id="more-818"></span>



<h2 class="wp-block-heading">How do we achieve this?</h2>



<p>To recap, the goal here is to test network connectivity on all VLANs on all ESXi hosts in a cluster. The best way to do this is by creating a VMKernel port on each Port Group, and pinging a separate IP on the network <em>from</em> that VMKernel port. Once the ping results are recorded, the VMKernel port is deleted. Rinse and repeat for every VLAN on every ESXi host. The script will pull all info required for creating the VMKernel ports from a CSV file.</p>



<h2 class="wp-block-heading">Example Output</h2>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="762" height="262" src="https://www.virtjunkie.com/wp-content/uploads/2019/10/image-1.png" alt="" class="wp-image-836" srcset="/wp-content/uploads/2019/10/image-1.png 762w, /wp-content/uploads/2019/10/image-1-300x103.png 300w" sizes="(max-width: 762px) 100vw, 762px" /><figcaption>This is an example of the output you will get from running this script</figcaption></figure>



<h2 class="wp-block-heading">CSV File Details</h2>



<p>The CSV file will contain the following fields: IP,&nbsp;GW,&nbsp;PG,&nbsp;NetMask,&nbsp;VLAN. Each row in the CSV will contain deails for a single VMKernel port. Here&#8217;s an example:</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="555" height="81" src="https://www.virtjunkie.com/wp-content/uploads/2019/10/image.png" alt="" class="wp-image-821" srcset="/wp-content/uploads/2019/10/image.png 555w, /wp-content/uploads/2019/10/image-300x44.png 300w" sizes="(max-width: 555px) 100vw, 555px" /></figure>



<p>In the example above, three VMKernel ports will be created on every ESXi host in the cluster, and a ping attempt will occur to the IP listed in the &#8220;gw&#8221; column from the entry in the &#8220;IP&#8221; column.</p>



<h2 class="wp-block-heading">The Script</h2>



<p>Now to the fun part, and why you&#8217;re actually here. First and foremost, you can see a copy of <a rel="noreferrer noopener" aria-label="GitHub Repository (opens in a new tab)" href="https://github.com/jonhowe/Virtjunkie.com" target="_blank">GitHub Repository</a>.</p>



<p>To run this script, you&#8217;ll need to pass variables as parameters or modify the default values. For example, you can run the script like this:</p>



<pre class="urvanov-syntax-highlighter-plain-tag">PS&gt; Test-ClusterNetworkConnectivity -vcenterserver &quot;myvcenterserver.local&quot; -vswitch &quot;distributed switch name&quot; -clustername &quot;my special cluster&quot; -csvpath c:\path\to\my.csv -verbose</pre>



<ul><li>vCenter Server (-vcenterserver)</li><li>The VDS in use (-vswitch)</li><li>The desired cluster you want to focus on (-clustername)</li><li>The CSV that contains info for the VMKernel ports (-csvpath)</li><li>If you want verbose output printed to the screen (-verbose:$true/$false)</li></ul>



<h2 class="wp-block-heading">Code Overview (and code)</h2>



<p><strong>Lines 1-17</strong><br>Documentation and parameters<br><br><strong>Lines 18-30</strong><br>Set up the environment, connect to vCenter, import the CSV, get the list of ESXi hosts to work with<br><br><strong>Lines 31&#8211;33</strong><br>Begin loop that goes through all ESXi hosts<br><br><strong>Lines 34-36</strong><br>Begin loop for each VMKernel port<br><br><strong>Lines 37-50</strong><br>Create splatting for variables<br>Instantiate object<br><br><strong>Lines 51-70</strong><br>Create the VMKernel adapter, test the ping, optionally print verbose logging<br><br><strong>Lines 71-80</strong><br>Add results to an array<br><br><strong>Lines 81-82</strong><br>Remove the VMKernel port<br><br><strong>Line 85-97</strong><br>This block exists to handle an error with creating the VMKernel port.<br><br><strong>Line 100</strong><br>Add the results of the ping test to an array<br><br><strong>Line 105-107</strong><br>Output the array of results and disconnect from the vcenter server</p>



<p></p>



<pre class="urvanov-syntax-highlighter-plain-tag">&amp;lt;#
.LINK http://www.virtjunkie.com/vsphere-test-cluster-connectivity/
.LINK https://github.com/jonhowe/Virtjunkie.com/blob/master/Test-ClusterNetworkConnectivity.ps1
#&gt;
param(
	$vcenterserver = &quot;vcenter67.pcm.net&quot;,
	$vswitch = &quot;UCS-vDS001&quot;,
	$clustername = &quot;UCS Cluster&quot;,
	$verbose = $false,
	$csvpath = &quot;C:\powershell\PCMlab_test_csv.csv&quot;
)

&amp;lt;#
***Fields in the CSV***
IP, GW, PG, netmask, vlan
#&gt;

#1.) connect to the vcenter
$credential = get-credential
$conn = connect-viserver -server $vcenterserver -credential $credential | out-null

#2.) Get a list of all VMhosts attached to the specified Switch and cluster
$vmhosts = get-vdswitch -name $vswitch | get-vmhost | Where-Object { $_.parent.name -eq $clustername }

#3.) Import the CSV file that has the IP, Gateway, Port Group, NetMask, and vLAN
$ALL_VMK_CSV_Rows = import-csv -path $csvpath

#Create array that stores results
$RS = @()

#3a.) Loop through each VMhost one at a time
foreach ($vmhost in $vmhosts)
{
	#Loop through each VMkernel in the CSV one at a time
	foreach ($ONE_VMK_CSV_ROW in $ALL_VMK_CSV_Rows)
	{
		#Splatting for parameters for new-vmhostnetworkadapter
		$NewVMKParams = @{
			VMHost = $vmhost
			PortGroup = $ONE_VMK_CSV_ROW.pg
			VirtualSwitch = $vswitch
			IP = $ONE_VMK_CSV_ROW.ip
			SubnetMask = $ONE_VMK_CSV_ROW.netmask
		}
		#Optional logging - disabled by default
		Write-Verbose -vb:$true -Message ($NewVMKParams | Out-String)
		
		#create new object to contain results
		$PingResults = New-Object System.Object

		#Test to see if the vmkernel port is created successfully.. if so, continue to test connectivity
		if ($vmkernel = new-vmhostnetworkadapter @NewVMKParams -ErrorAction SilentlyContinue)
		{
			#Get the newly created VMKernel adapter
			$vmkobj = Get-VMHostNetworkAdapter -VMHost $vmhost -VirtualSwitch (Get-VDSwitch -Name $vswitch) -VMKernel | 
				Where-Object { $_.devicename -eq $vmkernel.devicename }
		
			#Use ESXCli to emulate this command: vmkping -I [newly created vmkernel IP] TO: [Gateway IP Specified in the CSV]
			$esxcli = Get-EsxCli -VMHost $vmhost -V2
			$params = $esxcli.network.diag.ping.CreateArgs()
			$params.host = $ONE_VMK_CSV_ROW.GW
			$params.interface = $vmkobj.devicename
			#the $res variable contains the results of the ping.. if you want, you can see all of the result info by printing $res.summary
			$res = $esxcli.network.diag.ping.Invoke($params)
			
			#optional logging - disabled by default
			write-verbose -vb:$verbose -Message ($res.summary | Out-String)
			$output = (&quot;[$($vmhost.name)]: $($res.summary.Recieved / $res.summary.transmitted * 100)% success. Source: $($ONE_VMK_CSV_ROW.ip) Target: $($res.summary.hostaddr) || PG $($ONE_VMK_CSV_ROW.pg) (VLAN: $($ONE_VMK_CSV_ROW.vlan))&quot;)
			Write-Verbose -vb:$verbose -Message $output

			#Add properties to the object
			$PingResults | Add-Member -type NoteProperty -name Cluster -Value $clustername        
			$PingResults | Add-Member -type NoteProperty -name VMHost -Value $vmhost.name
			$PingResults | Add-Member -type NoteProperty -name SourceIP -Value $ONE_VMK_CSV_ROW.ip
			$PingResults | Add-Member -type NoteProperty -name TargetIP -Value $res.summary.hostaddr
			$PingResults | Add-Member -type NoteProperty -name PortGroup -Value $ONE_VMK_CSV_ROW.pg
			$PingResults | Add-Member -type NoteProperty -name VLAN -Value $ONE_VMK_CSV_ROW.vlan
			$PingResults | Add-Member -type NoteProperty -name PercentSuccess -Value ($res.summary.Recieved / $res.summary.transmitted * 100)
			$PingResults | Add-Member -type NoteProperty -name vSwitch -Value $vswitch
			
			#3d.) Remove vmkernel port
			remove-vmhostnetworkadapter -nic $vmkobj -confirm:$false
		}
		#if the vmkernel adapter is not created successfully, report the failure
		Else
		{
			#Optional Logging - disabled by default
			$output = (&quot;[$($vmhost.name)]: ERROR || PG $($ONE_VMK_CSV_ROW.pg) (VLAN: $($ONE_VMK_CSV_ROW.vlan)) does not exist on $($vswitch)&quot;)
			write-verbose -verbose:$verbose $output

			#Add properties to the object
			$PingResults | Add-Member -type NoteProperty -name Cluster -Value $clustername
			$PingResults | Add-Member -type NoteProperty -name VMHost -Value $vmhost.name
			$PingResults | Add-Member -type NoteProperty -name SourceIP -Value &quot;ERROR&quot;
			$PingResults | Add-Member -type NoteProperty -name TargetIP -Value &quot;ERROR&quot;
			$PingResults | Add-Member -type NoteProperty -name PortGroup -Value $ONE_VMK_CSV_ROW.pg
			$PingResults | Add-Member -type NoteProperty -name VLAN -Value $ONE_VMK_CSV_ROW.vlan
			$PingResults | Add-Member -type NoteProperty -name vSwitch -Value $vswitch
			$PingResults | Add-Member -type NoteProperty -name PercentSuccess -Value &quot;ERROR&quot;
		}

		#add object to array
		$RS += $PingResults

	} # end foreach ($ONE_VMK_CSV_ROW in $ALL_VMK_CSV_Rows)
} # end foreach ($vmhost in $vmhosts)

Write-Output $RS
#3e.) Disconnect from all vCenters
disconnect-viserver -server * -confirm:$false</pre>
<p>The post <a href="/2019/10/21/vsphere-test-cluster-connectivity/">Validate Network Connectivity Across A VMware Cluster</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2019/10/21/vsphere-test-cluster-connectivity/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>RVTools: Parse Multiple Outputs Using Powershell</title>
		<link>/2019/08/11/powershell-parse-rvtools/</link>
					<comments>/2019/08/11/powershell-parse-rvtools/#respond</comments>
		
		<dc:creator><![CDATA[Jon]]></dc:creator>
		<pubDate>Sun, 11 Aug 2019 15:00:14 +0000</pubDate>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Powershell]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[VMware]]></category>
		<guid isPermaLink="false">http://www.virtjunkie.com/?p=794</guid>

					<description><![CDATA[<p>If you haven&#8217;t used RVTools before, I&#8217;d definitely suggest taking a look. In case you&#8217;re one of the few that has not used it, it&#8217;s a quick tool to generate a point-in-time report of the inventory/configuration/health of a vSphere environment. While it&#8217;s one of the best tools out there for a quick and dirty report [&#8230;]</p>
<p>The post <a href="/2019/08/11/powershell-parse-rvtools/">RVTools: Parse Multiple Outputs Using Powershell</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you haven&#8217;t used <a rel="noreferrer noopener" aria-label=" (opens in a new tab)" href="https://www.robware.net/rvtools/" target="_blank">RVTools</a> before, I&#8217;d definitely suggest taking a look. In case you&#8217;re one of the few that has not used it, it&#8217;s a quick tool to generate a point-in-time report of the inventory/configuration/health of a vSphere environment. While it&#8217;s one of the best tools out there for a quick and dirty report of an environment, the challenge I often face is that it outputs <em>too much</em> data. The other challenge I&#8217;ve faced is that it&#8217;s incredibly difficult to combine and analyze data from multiple outputs. </p>



<span id="more-794"></span>



<p>I created a PowerShell script to help with this. The end result is a PowerShell object that can be consumed in any way you like. In a future post, I&#8217;ll show how to take this output and create a new Excel spreadsheet.</p>



<p>The image below is an example of what the script below generates.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="366" src="https://www.virtjunkie.com/wp-content/uploads/2019/08/image-4-1024x366.png" alt="" class="wp-image-813" srcset="/wp-content/uploads/2019/08/image-4-1024x366.png 1024w, /wp-content/uploads/2019/08/image-4-300x107.png 300w, /wp-content/uploads/2019/08/image-4-768x275.png 768w, /wp-content/uploads/2019/08/image-4.png 1484w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption>Example Output</figcaption></figure>



<p>As an FYI, we&#8217;ll need to install the <a rel="noreferrer noopener" aria-label=" (opens in a new tab)" href="https://www.powershellgallery.com/packages/ImportExcel" target="_blank">ImportExcel modul</a><a href="https://www.powershellgallery.com/packages/ImportExcel">e</a> in order to parse the excel file. If you want more information, check out the <a rel="noreferrer noopener" aria-label="github repository (opens in a new tab)" href="https://github.com/dfinke/ImportExcel" target="_blank">GitHub repository</a> for ImportExcel.</p>



<p>To run this script, at a minimum, you&#8217;ll need to modify the <code>$spreadsheetdir </code>variable to point to a directory that contains your RVTools outputs. This is a parameter, so it can be done by adding the <code>-spreadsheetdir "[path to my RVTools directory]"</code> if you like, or just feel free to modify the script.</p>



<p><strong>Lines 12-45</strong><br>Define column headers to be pulled for each spreadsheet<br><br><strong>Line 50</strong><br>Get the contents of the spreadsheet directory<br><br><strong>Line 54</strong><br>Loop through each spreadsheet in the spreadsheet directory<br><br><strong>Lines 58</strong><br>Get a distinct list of all clusters in the particular RVTools file. This will allow us to present the results one cluster at a time<br><br><strong>Lines 68-82</strong><br>Import the properties defined in lines 10-44 from the vInfo, vHost, and vDisk worksheet for later consumption<br><br><strong>Lines 84-101</strong><br>Do some math/formatting/voodoo to convert the values from RVTools into something useful<br><br><strong>Lines 63,64 and 103-110</strong><br>Take values from RVTools and calculations (from lines 84-101) and put them into a custom PowerShell object.</p>



<p>You can find the script in the public GitHub repository I keep all of the scripts for this site in:<br><a href="https://github.com/jonhowe/Virtjunkie.com">https://github.com/jonhowe/Virtjunkie.com</a></p>



<pre class="urvanov-syntax-highlighter-plain-tag">&amp;lt;#
.LINK http://www.virtjunkie.com/powershell-parse-rvtools/
.LINK https://github.com/jonhowe/Virtjunkie.com/blob/master/Parse-RVTools-Generic.ps1
#&gt;
param(
    # Migrate Powered Off VMs?
    [switch]$IncludePoweredOffVMs,

    # Directory that contains RVTools Exports
    $spreadsheetdir = &quot;/path/to/directory/&quot;,
    
    # Array that contains column headers to be gathered from the vHost worksheet
    $vHostProperties = @(
        'Host', 
        &quot;CPU usage %&quot;,
        &quot;Memory usage %&quot;,
        'model',
        &quot;Service Tag&quot;,
        &quot;Current EVC&quot;,
        &quot;Max EVC&quot;,
        &quot;# VMs&quot;,
        &quot;# Memory&quot;,
        &quot;# Cores&quot;,
        &quot;HT Active&quot;,
        &quot;vCPUs per Core&quot;
    ),

    # Array that contains column headers to be gathered from the vInfo worksheet
    $vInfoProperties = @(
        'VM',
        'Template',
        &quot;HW version&quot;,
        &quot;Provisioned MB&quot;,
        &quot;In Use MB&quot;,
        &quot;OS according to the VMware Tools&quot;,
        'memory'
    ),

    # Array that contains column headers to be gathered from the vDisk worksheet
    $vDiskProperties = @(
        &quot;vm&quot;,
        &quot;Raw LUN ID&quot;,
        &quot;Raw Comp. Mode&quot;,
        &quot;Shared Bus&quot;
    )

)

# Get all spreadsheets in the spreadsheet directory
$spreadsheets = $spreadsheetdir | Get-ChildItem

$rs = @()
# Loop through all spreadsheets in the spreadsheet dir
foreach ($sheet in $SpreadSheets)
{
    # Use the importexcel module to import the vCluster Worksheet
    # We do this as an easy way to get the 
    $vCluster = Import-Excel -Path $sheet -Sheet vCluster
    
    foreach ($cluster in $vCluster)
    {
        $ClusterDetails = New-Object System.Object
        $ClusterDetails | Add-Member -type NoteProperty -name vCenter -Value ($cluster.&quot;VI SDK Server&quot;)
        $ClusterDetails | Add-Member -type NoteProperty -name Cluster -Value $cluster.name 
       
        # Parse and store the properties defined in the $vInfoProperties array
        #   from the vInfo tab
        $vInfo = Import-Excel -Path $sheet -WorksheetName vInfo | 
            Where-Object { $_.Cluster -eq $cluster.name } | 
            Select-Object $vInfoProperties

        # Parse and store the properties defined in the $vHostProperties array
        #   from the vHost tab
        $vHost = Import-Excel -Path $sheet -WorksheetName vHost | 
            Where-Object { $_.Cluster -eq $cluster.name } | 
            Select-Object $vHostProperties

        # Parse and store the properties defined in the $vDiskProperties array
        #   from the vDisk tab
        $vDisk = Import-Excel -Path $sheet -WorksheetName vDisk | 
            Where-Object {$_.Cluster -eq $cluster.name } | 
            Select-Object $vDiskProperties

        # Calculate the sum of the column Provisioned MB from all rows in the vInfo tab, convert to GB, and round
        $TotalProvisionedGB = [math]::round(($vInfo | Measure-Object -Sum &quot;Provisioned MB&quot;).Sum / 1024, 2)
        $ClusterDetails | Add-Member -type NoteProperty -name TotalProvisionedGB -Value $TotalProvisionedGB        

        # Calculate the sum of the column In Use MB from all rows in the vInfo tab, convert to GB, and round
        $TotalInUseGB = [math]::round(($vInfo | Measure-Object -Sum &quot;In Use MB&quot;).Sum / 1024, 2)
        $ClusterDetails | Add-Member -type NoteProperty -name TotalInUseGB -Value $TotalInUseGB
        
        # Calculate average vCPU to PCPU, the total RAM in the cluster, and the average RAM Usage
        $vCPUtoPCPU = [math]::round(($vHost | Measure-Object -Average &quot;vCPUs per Core&quot;).average, 2)
        $clusterRAM = [math]::round(($vHost | Measure-Object -Sum &quot;# Memory&quot;).Sum / 1024, 2)
        $AvgClusterRamUsage = [math]::round(($vHost | Measure-Object -Average &quot;Memory Usage %&quot;).average, 2)

        #Detect RDMs and VMs with Shared Bus based on info in the vDisk sheet
        $RDMs = ($vDisk | ? { $_.&quot;Raw LUN ID&quot; -ne $null})
        $SharedBusVMs = ($vDisk | ? { $_.&quot;Shared Bus&quot; -ne $null -and $_.&quot;Shared Bus&quot; -ne &quot;noSharing&quot; -and $_.&quot;Shared Bus&quot; -ne 0})

        $clusterCoreCount = [math]::round(($cluster | Measure-Object -Sum &quot;NumCpuCores&quot;).sum,0)

        $ClusterDetails | Add-Member -type NoteProperty -name AvgClusterRamUsage -Value $AvgClusterRamUsage
        $ClusterDetails | Add-Member -type NoteProperty -name ClusterRamGB -Value $clusterRAM
        $ClusterDetails | Add-Member -type NoteProperty -name ClusterVMCount -Value $vInfo.count
        $ClusterDetails | Add-Member -type NoteProperty -name ClusterHostCount -Value ($vHost.count)
        $ClusterDetails | Add-Member -type NoteProperty -name TotalClusterCores -Value $clusterCoreCount
        $ClusterDetails | Add-Member -type NoteProperty -name vCPUtoPCPU -Value ($vCPUtoPCPU)
        $ClusterDetails | Add-Member -type NoteProperty -name RDMCount -Value ($RDMs.count)
        $ClusterDetails | Add-Member -type NoteProperty -name SharedBusVMs -Value ($SharedBusVMs.count)
        
        $rs += $ClusterDetails
    }
}

$rs</pre>
<p>The post <a href="/2019/08/11/powershell-parse-rvtools/">RVTools: Parse Multiple Outputs Using Powershell</a> appeared first on <a href="/">VirtJunkie</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>/2019/08/11/powershell-parse-rvtools/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
