<?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>Mario Giannini</title>
	<atom:link href="https://www.mariogiannini.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.mariogiannini.com</link>
	<description>In coding and motorcycles: Crashing sucks</description>
	<lastBuildDate>Thu, 22 Jan 2026 11:28:24 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.mariogiannini.com/wp-content/uploads/2019/06/favicon.ico</url>
	<title>Mario Giannini</title>
	<link>https://www.mariogiannini.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Unexpected reason for ACME certificate failures</title>
		<link>https://www.mariogiannini.com/2025/07/21/unexpected-reason-for-acme-certificate-failures/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Tue, 22 Jul 2025 00:24:23 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.mariogiannini.com/?p=492</guid>

					<description><![CDATA[I have been banging my head for hours with an issue where I have been unable to generate a certificate for a Proxmox server online. The final reason for the failure just took my by surprise. TL;DR; The Let&#8217;s Encrypt service was down, it wasn&#8217;t my fault. Check status here: https://letsencrypt.status.io/ Background For background, with &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2025/07/21/unexpected-reason-for-acme-certificate-failures/" class="more-link">Continue reading<span class="screen-reader-text"> "Unexpected reason for ACME certificate failures"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>I have been banging my head for hours with an issue where I have been unable to generate a certificate for a Proxmox server online.  The final reason for the failure just took my by surprise.</p>



<p><strong>TL;DR; </strong>The Let&#8217;s Encrypt service was down, it wasn&#8217;t my fault.  Check status here: <a href="https://letsencrypt.status.io/">https://letsencrypt.status.io/</a></p>



<p><strong>Background</strong></p>



<p>For background, with a Proxmox server you can setup an ACME account, and a Challenge plugin:</p>



<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="737" height="443" src="https://www.mariogiannini.com/wp-content/uploads/2025/07/image.png" alt="" class="wp-image-493" srcset="https://www.mariogiannini.com/wp-content/uploads/2025/07/image.png 737w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-300x180.png 300w" sizes="(max-width: 737px) 100vw, 737px" /></figure>



<p>The account is simple enough to make, you just give it a name, enter your email address, and agree to Terms of Service, and that&#8217;s done.  The GoDaddy challenge represents a GoDaddy DNS challenge plugin that I have already setup:</p>



<figure class="wp-block-image size-full"><img decoding="async" width="836" height="349" src="https://www.mariogiannini.com/wp-content/uploads/2025/07/image-1.png" alt="" class="wp-image-494" srcset="https://www.mariogiannini.com/wp-content/uploads/2025/07/image-1.png 836w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-1-300x125.png 300w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-1-768x321.png 768w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></figure>



<p>Then, within the Proxmox host, you should be able to order a certificate:</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="475" src="https://www.mariogiannini.com/wp-content/uploads/2025/07/image-3-1024x475.png" alt="" class="wp-image-496" srcset="https://www.mariogiannini.com/wp-content/uploads/2025/07/image-3-1024x475.png 1024w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-3-300x139.png 300w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-3-768x356.png 768w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-3.png 1061w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></figure>



<p>The problem is, that the request kept failing with the following:</p>



<blockquote class="wp-block-quote has-black-color has-cyan-bluish-gray-background-color has-text-color has-background has-link-color wp-elements-1adc007fd453630f0a4b7bf757a2e934 is-layout-flow wp-block-quote-is-layout-flow">
<p class="has-white-color has-black-background-color has-text-color has-background has-link-color wp-elements-4fc7301b5a75aa4f3b884ab5ca251c3a">Loading ACME account details<br>Placing ACME order<br>Order URL: https://acme-v02.api.letsencrypt.org/acme/order/0000000000/000000000000<br><br>Getting authorization details from &#8216;https://acme-v02.api.letsencrypt.org/acme/authz/0000000000/000000000000&#8217;<br>The validation for pm1.acme.net is pending!<br>[Mon Jul 21 19:41:33 EDT 2025] Adding record<br>[Mon Jul 21 19:41:44 EDT 2025] Added TXT record &#8216;azazazazaz-azazazaza-zazazazazazazazazazazaza&#8217; for &#8216;_acme-challenge.pm1.acme.net&#8217;.<br>Add TXT record: _acme-challenge.pm1.acme.net<br>Sleeping 120 seconds to wait for TXT record propagation<br>Triggering validation<br>Sleeping for 5 seconds<br>Remove TXT record: _acme-challenge.pm1.acme.net<br>TASK ERROR: validating challenge &#8216;https://acme-v02.api.letsencrypt.org/acme/authz/0000000000/000000000000&#8217; failed &#8211; status: invalid<br></p>
</blockquote>



<p>I finally decided to check the url that was reported:</p>



<p><a href="https://acme-v02.api.letsencrypt.org/acme/authz/0000000000/000000000000">https://acme-v02.api.letsencrypt.org/acme/authz/0000000000/000000000000</a></p>



<p>Once there, I saw json similar to the following:</p>



<pre class="wp-block-preformatted"><br>{<br>  "identifier": {<br>    "type": "dns",<br>    "value": "pm1.acme.net"<br>  },<br>  "status": "invalid",<br>  "expires": "2025-07-28T23:41:30Z",<br>  "challenges": [<br>    {<br>      "type": "dns-01",<br>      "url": "https://acme-v02.api.letsencrypt.org/acme/chall/0000000000/000000000000/gJaD_Q",<br>      "status": "invalid",<br>      "validated": "2025-07-21T23:43:44Z",<br>      "error": {<br>        "type": "urn:ietf:params:acme:error:serverInternal",<br>        "detail": "During secondary validation: Secondary validation RPC failed",<br>        "status": 500<br>      },<br>      "token": "azazazazazazazazazazazazazazazazazazazazazaz",<br>      "validationRecord": [<br>        {<br>          "hostname": "pm1.acme.net",<br>          "addressUsed": ""<br>        }<br>      ]<br>    }<br>  ]<br>}<br></pre>



<p>And what sticks out here, is the status &#8220;500&#8221; in the &#8220;error&#8221; tag.  This looks like a 50x server error.  Sure enough, I went to check the status of the Let&#8217;s Encrypt services here:</p>



<p><a href="https://letsencrypt.status.io">https://letsencrypt.status.io</a></p>



<p>And there, I see that Let&#8217;s Encrypt is experiencing problems: </p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="326" src="https://www.mariogiannini.com/wp-content/uploads/2025/07/image-4-1024x326.png" alt="" class="wp-image-497" srcset="https://www.mariogiannini.com/wp-content/uploads/2025/07/image-4-1024x326.png 1024w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-4-300x96.png 300w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-4-768x245.png 768w, https://www.mariogiannini.com/wp-content/uploads/2025/07/image-4.png 1378w" sizes="auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></figure>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>RackNerd, Rocky 8 VPS, slow boot</title>
		<link>https://www.mariogiannini.com/2024/03/25/racknerd-rocky-8-vps-slow-boot/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Mon, 25 Mar 2024 12:27:01 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.mariogiannini.com/?p=473</guid>

					<description><![CDATA[I have been testing a VPS from RackNerd.com lately, and I have to say that their support has been very good.  As I was testing a Rock 8 VPS, and I ran into long boot times with the VPS and decided to dig a little deeper.  Luckily RackNerd provides VNC so you can see the &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2024/03/25/racknerd-rocky-8-vps-slow-boot/" class="more-link">Continue reading<span class="screen-reader-text"> "RackNerd, Rocky 8 VPS, slow boot"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>I have been testing a VPS from RackNerd.com lately, and I have to say that their support has been very good.  As I was testing a Rock 8 VPS, and I ran into long boot times with the VPS and decided to dig a little deeper.  </p>



<p>Luckily RackNerd provides VNC so you can see the boot console, and I saw this:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="975" height="63" src="https://www.mariogiannini.com/wp-content/uploads/2024/03/image.png" alt="" class="wp-image-474" srcset="https://www.mariogiannini.com/wp-content/uploads/2024/03/image.png 975w, https://www.mariogiannini.com/wp-content/uploads/2024/03/image-300x19.png 300w, https://www.mariogiannini.com/wp-content/uploads/2024/03/image-768x50.png 768w" sizes="auto, (max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></figure>



<p>A start job is running for dev-disk and &#8220;1min 30s&#8221; is the key.  We can see that there is a start job delaying reboots by 90 seconds.  Looking into the journalctl data, I found these details:</p>



<p><code>[root@rn1 ~]# journalctl | grep 355fe974f1.device | grep timed</code></p>



<p><code>Mar 25 07:49:38 rockylinux8-minimal systemd[1]: dev-disk-by\x2duuid-2052dea6\x2d1b40\x2d4c49\x2d81e1\x2d4b355fe974f1.device: Job dev-disk-by\x2duuid-2052dea6\x2d1b40\x2d4c49\x2d81e1\x2d4b355fe974f1.device/start timed out.</code></p>



<p>Most of the articles I came across had to do with a bad or missing partition and using fstab to fix it,  or changing DefaultTimeoutStartSec in the system.conf file.  But these didn&#8217;t fit my issue exactly, and I wanted to know why this particular device (&#8230;355fe974f1.device) was the issue, when I had no device with this UID.</p>



<p>I took a look at the grub file:</p>



<p><code>[root@rn1 ~]# cat /etc/default/grub<br>GRUB_TIMEOUT=5<br>GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"<br>GRUB_DEFAULT=saved<br>GRUB_DISABLE_SUBMENU=true<br>GRUB_TERMINAL_OUTPUT="console"<br>GRUB_CMDLINE_LINUX="crashkernel=auto <em><mark style="background-color:rgba(0, 0, 0, 0)" class="has-inline-color has-vivid-red-color">resume=UUID=2052dea6-1b40-4c49-81e1-4b355fe974f1</mark></em> net.ifnames=0 biosdevname=0 rhgb quiet"<br>GRUB_DISABLE_RECOVERY="true"<br>GRUB_ENABLE_BLSCFG=true</code></p>



<p>The <em>resume</em> option was where the bad device ID was comming from.  The resume option has to do with hiberntation mode, and since this was a server there should be no hibernation mode.  So, I removed the &#8216;resume&#8217; section from the file.</p>



<p>I then went to run grub-update, but it wasn&#8217;t found.  Luckily, this is a simple shell script, so I recreated it:</p>



<p><code>vi /usr/sbin/grub-update</code></p>



<p>Add to this file:</p>



<p><code>#!/bin/sh<br>set -e<br>exec grub2-mkconfig -o /boot/grub2/grub.cfg "$@"</code></p>



<p>Then add executable permission to it:</p>



<p><code>chmod +x /usr/sbin/grub-update</code></p>



<p>And finally, run the new script, and reboot:</p>



<p><code>[root@rn1 ~]# /usr/sbin/grub-update</code><br><code>[root@rn1 ~]# </code>reboot</p>



<p>The reboot now takes about 10 to 15 seconds, instead of a minute and a half.</p>



<p></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Setup mRemoteNG for AWS ssh access</title>
		<link>https://www.mariogiannini.com/2020/11/01/setup-mremoteng-for-aws-ssh-access/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Sun, 01 Nov 2020 15:50:02 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.mariogiannini.com/?p=353</guid>

					<description><![CDATA[I use mRemoteNG as my primary tool for remote access to both Linux and Windows machines. I recently had a need to set it up to access a Linux VM created on Amazon&#8217;s AWS EC2 services. It mostly went smoothly, except I did run into one issue with permissions. Specifically, the EC2 VM had ssh &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2020/11/01/setup-mremoteng-for-aws-ssh-access/" class="more-link">Continue reading<span class="screen-reader-text"> "Setup mRemoteNG for AWS ssh access"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>I use mRemoteNG as my primary tool for remote access to both Linux and Windows machines.  I recently had a need to set it up to access a Linux VM created on Amazon&#8217;s AWS EC2 services.  It mostly went smoothly, except I did run into one issue with permissions.</p>



<p>Specifically, the EC2 VM had ssh access controlled via a private key, and not your typical password login.  This allows you to restrict access not by giving someone the login and password, but by giving them a specific private key file.  </p>



<p>To jump ahead, my mistake was that I placed the key file into a program files folder where special permissions were required.  When mRemoteNG was loading that file, the permissions were actually too open, and putty would complain about it without showing a message in mRemoteNG. When I ran the manual ssh attempt, I saw the message:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="233" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture01.png" alt="" class="wp-image-354" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture01.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture01-300x112.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>Again, that&#8217;s because of where I placed the private key.  If you place it in your documents folder, you will not have this issue.  There are 4 key steps to follow here, some of which you may not need:</p>



<ul class="wp-block-list"><li><a href="#CreateanAWSVirtualMachine" data-type="internal" data-id="#CreateanAWSVirtualMachine">Create an AWS Virtual Machine</a></li><li><a href="#ConvertthePEMfiletoPPK" data-type="internal" data-id="#ConvertthePEMfiletoPPK">Convert the PEM file to PPK</a></li><li><a href="#SetupPuttywiththesettings" data-type="internal" data-id="#SetupPuttywiththesettings">Setup Putty with the settings</a></li><li><a href="#SetupmRemoteNGtousenewPuttysetting" data-type="internal" data-id="#SetupmRemoteNGtousenewPuttysetting">Setup mRemoteNG to use new Putty setting</a></li></ul>



<p id="-CreateanAWSVirtualMachine"><strong>Create an AWS Virtual Machine</strong></p>



<p>In the AWS dashboard, select to create a new instance with <em>Launch Instance</em>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="188" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture02.png" alt="" class="wp-image-355" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture02.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture02-300x90.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>We will select a RedHat Linux instance:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="83" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture03.png" alt="" class="wp-image-356" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture03.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture03-300x40.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>For this demo, select a Free tier instance:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="155" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture04.png" alt="" class="wp-image-357" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture04.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture04-300x75.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>Select <em>Review and Launch </em>and then <em>Launch:</em></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="533" height="94" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture05.png" alt="" class="wp-image-358" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture05.png 533w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture05-300x53.png 300w" sizes="auto, (max-width: 533px) 100vw, 533px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="247" height="64" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture06.png" alt="" class="wp-image-359"/></figure>



<p>You will be prompted to create a key pair with the following dialog:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="461" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture07.png" alt="" class="wp-image-360" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture07.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture07-300x222.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>Enter a new key pair name (or reuse existing one. We decided on DemoVHost):</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="118" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture08.png" alt="" class="wp-image-361" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture08.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture08-300x57.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>This will download a file with the Key pair name. Make sure to save this file somewhere safe, you will need it later:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="239" height="58" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture09.png" alt="" class="wp-image-362"/></figure>



<p>Click the <em>Launch Instance button</em>. Back in the instances, your new VM should start soon:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="231" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture10.png" alt="" class="wp-image-363" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture10.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture10-300x111.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>In the instance details, make note of the DNS name:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="49" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture12.png" alt="" class="wp-image-364" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture12.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture12-300x24.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>You can now proceed to setup Putty settings.</p>



<p>You can not proceed to <em>Convert the PEM file to PPK.</em></p>



<p id="ConvertthePEMfiletoPPK"><strong>Convert the PEM file to PPK</strong></p>



<p>You need to convert the PEM file we downloaded earlier into a PPK file.&nbsp; Wherever you store this file, you need to make sure that you are the only person who has access permissions to it.&nbsp; That may mean running puttygen as an administrator, and after this process changing the generated ppk file permissions so that only you have access to it (or, you can just store it in your documents folder somewhere).</p>



<p>Run the puttygen program.&nbsp; I downloaded mine from<a href="https://www.putty.org/" target="_blank" rel="noreferrer noopener"> https://www.putty.org/</a>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="480" height="471" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture13.png" alt="" class="wp-image-365" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture13.png 480w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture13-300x294.png 300w" sizes="auto, (max-width: 480px) 100vw, 480px" /></figure>



<p>In Putty Generator, select <em>Conversions</em> / <em>Import Key</em>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="401" height="168" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture14.png" alt="" class="wp-image-367" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture14.png 401w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture14-300x126.png 300w" sizes="auto, (max-width: 401px) 100vw, 401px" /></figure>



<p>Select the PEM file you just downloaded from AWS:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="554" height="207" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture15.png" alt="" class="wp-image-368" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture15.png 554w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture15-300x112.png 300w" sizes="auto, (max-width: 554px) 100vw, 554px" /></figure>



<p>In the next dialog, you can enter a passphrase, or leave it blank (you will get a warning), but click the <em>Save private key </em>button:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="627" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture16-1.png" alt="" class="wp-image-370" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture16-1.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture16-1-300x300.png 300w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture16-1-150x150.png 150w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture16-1-100x100.png 100w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>You can close the generator now, and proceed to <em>Setup Putty with the settings</em>.</p>



<p id="SetupPuttywiththesettings"><strong>Setup Putty with the settings</strong></p>



<p>In mRemoteNG, select the <em>Tools / Options</em> menu choice:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="304" height="184" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture17-1.png" alt="" class="wp-image-371" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture17-1.png 304w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture17-1-300x182.png 300w" sizes="auto, (max-width: 304px) 100vw, 304px" /></figure>



<p>Select the <em>Advanced</em> option, and click the <em>Launch Putty</em> button:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="250" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture18.png" alt="" class="wp-image-372" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture18.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture18-300x120.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>In Putty, go to the <em>Connection </em>/ <em>SSH</em> / <em>Auth</em> item in the left bar, and select the <em>Browse…</em> button, and elect the PPK file that you generated previously:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="451" height="438" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture20.png" alt="" class="wp-image-373" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture20.png 451w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture20-300x291.png 300w" sizes="auto, (max-width: 451px) 100vw, 451px" /></figure>



<p>Go to the <em>Session</em> item on the left panel, enter a new name in the <em>Saved Sessions</em> field, then click <em>Save</em>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="458" height="444" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture22.png" alt="" class="wp-image-374" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture22.png 458w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture22-300x291.png 300w" sizes="auto, (max-width: 458px) 100vw, 458px" /></figure>



<p>Confirm your new name is in the <em>Saved Sessions</em> area, and click <em>Close</em>.</p>



<p>You can now proceed to Setup mRemoteNG to use new Putty setting.</p>



<p id="SetupmRemoteNGtousenewPuttysetting"><strong>Setup mRemoteNG to use new Putty setting</strong></p>



<p>In the configuration settings for your mRemoteNG connection, update the following:</p>



<ul class="wp-block-list"><li>Set <em>Hostname/IP</em> to the DNS name noted earlier.</li><li>Set <em>Username</em> to ec2-user</li><li>Set<em> Putty Session</em> to the new settings you saved previously in putty</li></ul>



<p><br></p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="477" height="421" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture24.png" alt="" class="wp-image-375" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture24.png 477w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture24-300x265.png 300w" sizes="auto, (max-width: 477px) 100vw, 477px" /></figure>



<p>When you connect, you will get the normal putty message about the host key not being cached.&nbsp; Just click <em>Yes</em>:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="371" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture25.png" alt="" class="wp-image-376" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture25.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture25-300x178.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>



<p>You should now be connected remotely:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="624" height="145" src="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture26.png" alt="" class="wp-image-377" srcset="https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture26.png 624w, https://www.mariogiannini.com/wp-content/uploads/2020/11/AWS_Picture26-300x70.png 300w" sizes="auto, (max-width: 624px) 100vw, 624px" /></figure>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>A program to download PBase images</title>
		<link>https://www.mariogiannini.com/2019/10/16/a-program-to-download-pbase-images/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Wed, 16 Oct 2019 16:00:35 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.mariogiannini.com/?p=314</guid>

					<description><![CDATA[I’ve been using PBase.com to store my images for more than 10 years. For various reasons, I’m considering moving from PBase to my own server. The task of trying to recreate the 70+ galleries containing several thousand images from my original files that are now in the high tens of thousands of files is a &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2019/10/16/a-program-to-download-pbase-images/" class="more-link">Continue reading<span class="screen-reader-text"> "A program to download PBase images"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>I’ve been using PBase.com to store my images for more than 10 years.  For various reasons, I’m considering moving from PBase to my own server.  The task of trying to recreate the 70+ galleries containing several thousand images from my original files that are now in the high tens of thousands of files is a daunting task.</p>



<p>I started to look for a program to download my PBase library of images and galleries, but couldn’t find any options or a feature in PBase to allow me to download all my images.  So, I decided to write one in C# using WinForms.</p>



<p>The source code and a pre-built executable are all available on Github at <a rel="noopener noreferrer" href="https://github.com/MarioGiannini/MGPBaseDownloader" target="_blank">https://github.com/MarioGiannini/MGPBaseDownloader</a></p>



<p>The user interface is pretty simple, and just contains a text box for the URL of the pbase user root gallery and a folder where to store the downloaded file.  I&#8217;ll be honest and further state that there is basically zero error handling for things like selecting an invalid (or even blank) URL or destination folder.</p>



<p>The majority of the work is done by the <em>PBaseDownloader </em>class, and the <em>ProcessUrlEx </em>function specifically.  The <em>ProcessUrlEx </em>is a recursive function that loads a web page using <em>WebClient </em>and then parses it using <em>HtmlAgilityPack.HtmlDocument</em> methods.  When it identifies a thumnail it determines if the thumbnail leads to another gallery or to an image display page, and then handles it accordingly.  When the thumbnail refers to another gallery, then <em>ProcessUrlEx </em>calls itself recursively to continue processing that sub-gallery.</p>



<p>The HtmlAgilityPack was added using the Nuget package manager.</p>



<p>Below is some pseudo code that demonstrates downloading the page and parsing it:</p>



<pre class="wp-block-preformatted">using (WebClient Client = new WebClient())
{
   String Page = Client.DownloadString(url);  // Download the web page
   HtmlAgilityPack.HtmlDocument Doc = new HtmlAgilityPack.HtmlDocument();
   Doc.LoadHtml(Page);
   ItemNodes = Doc.DocumentNode.SelectNodes("//td[@class='thumbnail']");
   if (ItemNodes == null)
      Results.AppendText( "&gt;&gt; No images or folders\r\n");
   else
   {
      foreach (HtmlNode Node in ItemNodes)
      {
         ItemLink = ExtractString( Node.InnerHtml, "href=");
      }
   }
}</pre>



<p>The example above uses the <em>SelectNodes </em>method to iterate the <em>td </em>elements with a class of ‘thumbnail’ to help iterate the thumbnail elements that link to another gallery or to an image display. </p>



<p>Note: The <em>ExtractString </em>method in the sample code is a method in the  PBaseDownloader class of the source code.  It simply extracts the quoted portion of a string after an attribute like &#8220;href=&#8221;.</p>



<p>The pseudo code below demonstrates how to identify a JPG link (from PBase formatting) and download the file:</p>



<pre class="wp-block-preformatted">HtmlNode jpgnode = ImageDoc.DocumentNode.SelectSingleNode("//div[@id='imgdiv']");
if (jpgnode != null)
{
   String jpgLink = ExtractString(jpgnode.InnerHtml, "src=");
   Client.DownloadFile( jpgLink, SaveFile );
}</pre>



<p>When iterating though the elements of a page, each element (an image page or a sub gallery) is assigned a simple sequential index, and that index becomes a part of the folder or image name.  This is done to help maintain the order of the items as they appear.  When the folder or filenames are created, a zero-padded prefix is used to insure identical ordering (despite in Explorer where folders and files are separated into groups).  For example:</p>



<pre class="wp-block-preformatted">001-Cross Country
    001.jpg
    001.txt
    002.jpg
    002.txt
002-People
    001.jpg
    001.txt
    002.jpg
    002.txt
    003.jpg
    003.txt</pre>



<p>The .txt file corresponding to the JPG files contain the title and EXIF data (if available) that were also parsed from the HTML page.  In addition, each gallery folder contains the thumbnail of the folder (Thumbnail.jpg) and the description that the PBase user added for the gallery (Description.txt).</p>



<p>I have not tested it extensively, but it’s working today on the few PBase accounts I’ve tested it with. In time, PBase may change their formatting and this could potentially break the HTML parsing logic.  This is a common downside to web-scraping programs.</p>



<p>In general, I frown on the process of web scraping, but sometimes when you want a convenient way to gather your own information from a site, it may be the only way of doing it.  Obviously, such a program could be used to go and ‘steal’ data that’s already in the public, and I hope that nobody plans on that.  I just thought this was interesting demonstration of some basic operations in web scraping with C#.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Macrium to the rescue</title>
		<link>https://www.mariogiannini.com/2019/02/10/macrium-to-the-rescue/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Sun, 10 Feb 2019 14:06:10 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://www.mariogiannini.com/?p=307</guid>

					<description><![CDATA[Not long ago, I took over a PC used for administrative purposes. It has several outdated proprietary programs to manage things like the phone system, wireless routers beyond EOL, as well as my own software development IDE setups. The PC was previously being backed up by Acronis True Image, which I have used but have &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2019/02/10/macrium-to-the-rescue/" class="more-link">Continue reading<span class="screen-reader-text"> "Macrium to the rescue"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>Not long ago, I took over a PC used for administrative purposes.  It has several outdated proprietary programs to manage things like the phone system, wireless routers beyond EOL, as well as my own software development IDE setups.  The PC was previously being backed up by Acronis True Image, which I have used but have never been a fan of.  I decided to switch it to the Macrium Reflect program. I setup Macrium to do a C: drive backup once a week to an external drive.  It was a pretty painless process, running as a scheduled task, and I never got the annoying pop-ups that Acronis seemed to display.   And then, the inevitable happened: one day my computer was simply dead. The motherboard was dead, and I had tons of work that I needed to get to. </p>



<p><strong>Rescued</strong><br>Macrium saved my bacon by allowing me to go from a dead computer to operational status in about 15 minutes.  I pulled the hard drive containing the drive image, put it into a SATA/USB enclosure I had, and used Macrium to launch the drive image as a virtual machine.  It is very relieving to see your dead computer come back to life as a virtual machine.  As my data was backed up nightly, I was able to continue working on projects with apps and IDEs as needed for the rest of the week, as I awaited a replacement motherboard. </p>



<p><strong>Assisted</strong><br>As my computer was used for various systems administration and software development with several IDEs, setting up a replacement can easily take 3 or 4 full days.  I wanted to purchase the exact same motherboard in hopes that I could just swap it out and regain full operation.  Unfortunately, the motherboard was discontinued, so I purchased the most similar motherboard I could from the same manufacturer.  I also opted for a larger SSD as an upgrade since I was running low on the original. Macrium assisted by allowing me to clone the old SSD to the new one.  Pretty standard stuff really, but Macrium just made it a simple process.  With the new SSD installed, and the new motherboard, I booted up everything and was greeted with a fully operational version of my old PC. </p>



<p><strong>Downside</strong><br>The only real downside I had was that because the PC was using an OEM System Builder version of windows, replacing the motherboard meant I had to activate Windows.  And of course, OEM System Builders don’t reactivate on a new computer, only on the first computer that they were activated with.  So, I had to purchase another copy of Windows 10 OEM System Builder. </p>



<p><strong>Summary</strong><br>We all know the importance of backups.  But, these Macrium drive images allowed me to go one step further.  Thanks to the fact that I have some extra hardware at my disposal (like a spare PC and some SATA/USB enclosures), I was able to go from a dead PC to normal in a few minutes.  Granted, it was a virtual machine of my PC, and running slower than normal, but at least it allowed me to get my work done when I needed.  I am now a paying member of the Macrium fan club. </p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Multithreaded Shell Script</title>
		<link>https://www.mariogiannini.com/2019/01/15/multithreaded-shell-script/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Tue, 15 Jan 2019 19:04:25 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.mariogiannini.com/?p=278</guid>

					<description><![CDATA[I had a queue of jobs that I wanted to process, but I wanted to utilize more than one thread while also avoiding just creating a thread for every job in the queue.&#160; The goal is to implement a scalable system both in terms of adding cores to a virtual machine but also in adding &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2019/01/15/multithreaded-shell-script/" class="more-link">Continue reading<span class="screen-reader-text"> "Multithreaded Shell Script"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>I had a queue of jobs that I wanted to process, but I wanted to utilize more than one thread while also avoiding just creating a thread for every job in the queue.&nbsp; The goal is to implement a scalable system both in terms of adding cores to a virtual machine but also in adding additional machines (discussed later).</p>



<p>Proof of Value: I have a process that uses tesseract to convert a bunch of JPGs into PDF files, then pdfunite to join those into a single PDF.&nbsp; Working on a single file took 81 seconds, but working with 4 threads (on a 4-core VM), I was able to create 4 identical PDFs in about 104 seconds.&nbsp; That’s a 400% increase in throughput with only a 28% increase in time. As the processing power and core count increases, we can expect improved throughput with additional threads.</p>



<p>I am going to use the number of cores on the computer to determine how many simultaneous threads my script should be limited to.&nbsp; This is absolutely a ‘best guess’ scenario, and you may prefer to run two or more times as many cores on the computer.&nbsp; I am making no attempt to spread out the threads or identify how busy a core is (the OS should be doing that).&nbsp; In reality, multiple threads are already running on all the cores from different processes.</p>



<p>The script will be run on a cron job, every minute.&nbsp; Once run, it will run for 50 years, or until the server is shut down.&nbsp; However, it will use an exclusive lock to make sure that only one instance of the script is running at a time (except for the child threads of course).</p>



<p>The demo script will scan for a set of files, then fork itself (once for each thread) to sleep for several random seconds and then delete the file.</p>



<p>The script starts with a standard header and the declaration of a temp folder for our files:</p>



<pre class="wp-block-preformatted">#!/bin/bash<br>#define our own tmp folder name, should be unique<br>tmpdir='/tmp/mtdemo'</pre>



<p>Then, it tests to see if we got a command line argument.&nbsp; If we did, it means the script was invoked with information to do some job in the child thread.&nbsp; In our example, we’re just sleeping and deleting some flag and data files to simulate doing real work:</p>



<pre class="wp-block-preformatted">if [ "$1" != "" ]; then<br>    # If we got an argument, we were told to do something. This is where the child works:<br>    RANDOM=$$<br>    R=$(($(($RANDOM%8))+2))<br>    echo "Child thread in slot $2 started with $1.  Simulating processing with sleep $R"<br>    sleep "$R"<br>    # clean up the files that control synchronization<br>    echo "Child thread in slot $2 finished with $1."<br>    trap "rm -f ~/$1; rm -f $tmpdir/$1; rm -f $tmpdir/slot.$2" exit<br> else</pre>



<p>This demo code will show you what ‘slot’ the thread is
running in, and the file it’s processing, along with start and stop
messages.&nbsp; Note how we’re using trap to
clean up any orphaned files in case of an error.</p>



<p>The following code snippet shows how to insure we are running only a single copy of the main file monitor that will invoke a child thread as needed. The logic for identifying a free ‘slot’ and a file to be processed will be located within the do … done block below:</p>



<pre class="wp-block-preformatted">(<br>    # Wait for lock on /tmp/mtdemo_exclusivelock (fd 200) for 1 second<br>    flock -x -w 1 200 || exit 1<br>    end=$(date -ud "50 year" +%s)<br>    while [[ $(date -u +%s) -le $end ]]<br>    do<br>       # If needed, invoke ourselves as a forked process (&amp;) with some parameters:<br>       if something<br>          $0 "$key" "$slot"&amp;<br>       fi<br>    done<br> ) 200&gt;"/tmp/mtdemo_exclusivelock"</pre>



<p>The parens will create a code block that will be identified as a file handle of 200 on the file /tmp/mtdemo_exclusivelock.&nbsp; Inside that block, it uses flock to attempt to lock the file, and if the lock can’t be obtained then <em>exit</em> is invoked, otherwise it proceeds into the block.&nbsp; The <em>end</em> variable and the <em>while</em> loop create a loop that will execute for 50 years (or until the server shuts down).</p>



<p>In order to identify a free ‘slot’ for threading, we will first get the number of cores with the following:</p>



<pre class="wp-block-preformatted">cpus=$(nproc)<br></pre>



<p>Then, we use files to try and identify free slots.&nbsp; For example, let’s say we have 4 cores.&nbsp; We will test to see if the file slot.1 exists.&nbsp; If it does, then that means a thread is
already running on that slot, and we proceed to test for slot.2.&nbsp; If it doesn’t exist, then we’re going to
start a thread with ‘1’ as a parameter, and the child thread will know to
create slot.1 at the start of it’s processing, and delete it at the end.&nbsp; The child process will create and destroy the
slot.1 file as a flag.</p>



<p>Here’s the loop that tests for a free slot:</p>



<pre class="wp-block-preformatted">slot=0<br>for i in $(seq 1 $cpus); do<br>   if [ ! -f "$tmpdir/slot.$i" ]; then<br>      slot=$i<br>   fi<br>done<br></pre>



<p>At the end of the loop above, if slot is &gt; 0, then a free slot was found.&nbsp; The bash test would be:</p>



<pre class="wp-block-preformatted">if [ $slot -gt 0 ]; then<br>   ... Do something<br>fi</pre>



<p>Now, the <em>Do something</em> comment above is going to look for files to process.&nbsp; For our demo, we’re just going to look for .tmp files in our home folder.&nbsp; The ‘Processing’ that will be done for each file is the same sleep and file delete with messages discussed above.&nbsp; This loop shows how we look for .tmp files to ‘process’:</p>



<pre class="wp-block-preformatted">for d in ~/*.tmp ; do<br>   [ -f "$d" ] || continue<br>   key=$(basename -- "$d")<br>   if [ ! -f "$tmpdir/$key" ]; then<br>      echo "Working $d" &gt; "$tmpdir/slot.$slot"<br>      echo "Working slot $slot" &gt; "$tmpdir/$key"<br>      $0 "$key" "$slot"&amp;<br>      break;<br>   fi<br>done</pre>



<p>Here’s a key component:&nbsp;
When a file to process is found, the script runs itself in a fork
(&amp;) passing to it the name of the file to process.&nbsp; If no files are found, no fork takes place.</p>



<p>In order to test the script, let’s first make several bogus .tmp files in our home folder (make twice as many as nproc reports, which is 4 in my case):</p>



<pre class="wp-block-preformatted">echo Bogus File &gt; 1.tmp<br>echo Bogus File &gt; 2.tmp<br>echo Bogus File &gt; 3.tmp<br>echo Bogus File &gt; 4.tmp<br>echo Bogus File &gt; 5.tmp<br>echo Bogus File &gt; 6.tmp<br>echo Bogus File &gt; 7.tmp<br>echo Bogus File &gt; 8.tmp</pre>



<p>With the script in the home folder, run it.&nbsp; The results should look like this:</p>



<pre class="wp-block-preformatted">[root@fpsrv5 ~]# ./demo.sh<br>Cores found: 4<br>Child thread in slot 4 started with 1.tmp.  Simulating processing with sleep 9<br>Child thread in slot 3 started with 2.tmp.  Simulating processing with sleep 3<br>Child thread in slot 2 started with 3.tmp.  Simulating processing with sleep 4<br>Child thread in slot 1 started with 4.tmp.  Simulating processing with sleep 4<br>Child thread in slot 3 finished with 2.tmp.<br>Child thread in slot 3 started with 5.tmp.  Simulating processing with sleep 7<br>Child thread in slot 2 finished with 3.tmp.<br>Child thread in slot 1 finished with 4.tmp.<br>Child thread in slot 2 started with 6.tmp.  Simulating processing with sleep 7<br>Child thread in slot 1 started with 7.tmp.  Simulating processing with sleep 5<br>Child thread in slot 4 finished with 1.tmp.<br>Child thread in slot 4 started with 8.tmp.  Simulating processing with sleep 4<br>Child thread in slot 1 finished with 7.tmp.<br>Child thread in slot 3 finished with 5.tmp.<br>Child thread in slot 2 finished with 6.tmp.<br>Child thread in slot 4 finished with 8.tmp.</pre>



<p>So we can see the slots 4, 3, 2, and 1 were child threads for files 1.tmp, 2.tmp, 3.tmp, and 4.tmp respectively.&nbsp; Note how slot 3 started on 2.tmp with a 3 second sleep.&nbsp; Because of that, it finished first, and you can see that slot 3 then started processing file 5.tmp (with a sleep of 7 seconds).</p>



<p>To complete the practical use of this script, we would remove any of the information &#8216;echo&#8217; statements we didn&#8217;t want, and add it to a cron job so that it would run all the time.</p>



<p><strong>Entire Script</strong></p>



<pre class="wp-block-preformatted">#!/bin/bash<br>#define our own tmp folder name, should be unique<br>tmpdir='/tmp/mtdemo'<br> <br>if [ "$1" != "" ]; then<br>   # If we got an argument, we were told to do something. This is where the child works:<br>   RANDOM=$$<br>   R=$(($(($RANDOM%8))+2))<br>   echo "Child thread in slot $2 started with $1.  Simulating processing with sleep $R"<br>   sleep "$R"<br>   # clean up the files that control synchronization<br>   echo "Child thread in slot $2 finished with $1."<br>   trap "rm -f ~/$1; rm -f $tmpdir/$1; rm -f $tmpdir/slot.$2" exit<br> else<br>   #execute the following only if we get an exclusive lock.  The first run will hold the lock for 50 years.<br>   (<br>      # Wait for lock on  /tmp/mtdemo_exclusivelock (fd 200) for 1 second<br>      flock -x -w 1 200 || exit 1<br> <br>      #Start by wiping out the synch files, incase we were rebooted mid-job<br>      rm -r -f "$tmpdir"<br>      mkdir -p "$tmpdir"<br> <br>      #determine how many processors we have to control thread count<br>      cpus=$(nproc)<br>      echo "Cores found: $cpus"<br>      end=$(date -ud "50 year" +%s)<br>      while [[ $(date -u +%s) -le $end ]]<br>      do<br>         #Locate a free slot for a CPU based on file existance<br>         slot=0<br>         for i in $(seq 1 $cpus); do<br>            if [ ! -f "$tmpdir/slot.$i" ]; then<br>               slot=$i<br>            fi<br>         done<br> <br>         #if we got a free slot, then do we have a file that needs processing?<br>         if [ $slot -gt 0 ]; then<br>            for d in ~/*.tmp ; do<br>               [ -f "$d" ] || continue<br>               key=$(basename -- "$d")<br>               if [ ! -f "$tmpdir/$key" ]; then<br>                  echo "Working $d" &gt; "$tmpdir/slot.$slot"<br>                  echo "Working slot $slot" &gt; "$tmpdir/$key"<br>                  $0 "$key" "$slot"&amp;<br>                  break;<br>               fi<br>            done<br>         fi<br>      done<br>   ) 200&gt;"/tmp/mtdemo_exclusivelock"<br>fi<br></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Too many files open</title>
		<link>https://www.mariogiannini.com/2018/11/03/too-many-files-open/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Sat, 03 Nov 2018 19:22:07 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.mariogiannini.com/?p=271</guid>

					<description><![CDATA[While working with a file processing server, I had a webpage execute a pdfunite command to join 1,100 PDF files into a single large PDF (it was invoked via curl from a cron job). The script failed, and I found that it was displaying “Too many open files” in its processing. It turns out that &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2018/11/03/too-many-files-open/" class="more-link">Continue reading<span class="screen-reader-text"> "Too many files open"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>While working with a file processing server, I had a webpage execute a pdfunite command to join 1,100 PDF files into a single large PDF (it was invoked via curl from a cron job).  The script failed, and I found that it was displaying “Too many open files” in its processing.  It turns out that running pdfunite with so many files was exceeding the maximum open file count for Linux.</p>



<p>I increased the per-user limits by editing the /etc/security/limits.conf file and adding the following to the end of the file:</p>



<pre class="wp-block-preformatted">*         hard    nofile      500000 <br>*         soft    nofile      500000 <br>root      hard    nofile      500000 <br>root      soft    nofile      500000 </pre>



<p>I rebooted, because I could, and then verified the maximum open file count using the ulimit command:</p>



<pre class="wp-block-preformatted">#su - apache -c 'ulimit -aHS' -s '/bin/bash' | grep 'open files'<br>open files                      (-n) 500000 </pre>



<p>Attempting to submit the files for processing again worked without a problem.
</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>PDF To JPG</title>
		<link>https://www.mariogiannini.com/2018/08/13/pdf-to-jpg/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Mon, 13 Aug 2018 17:39:02 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.mariogiannini.com/?p=260</guid>

					<description><![CDATA[I had a need to extract the pages of a PDF as JPG images. I have a Linux VM setup already with tesseract as an OCR server, so I decided to add this ability to it. The first choice was to install ImageMagick and use it&#8217;s convert utility. After using yum install ImageMagick, when I &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2018/08/13/pdf-to-jpg/" class="more-link">Continue reading<span class="screen-reader-text"> "PDF To JPG"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>I had a need to extract the pages of a PDF as JPG images.  I have a Linux VM setup already with tesseract as an OCR server, so I decided to add this ability to it.  The first choice was to install ImageMagick and use it&#8217;s convert utility.</p>



<p>After using yum install ImageMagick, when I tried to convert with ICC files like below;</p>



<pre class="wp-block-preformatted"><block>convert -verbose -density 300 -colorspace rgb SaleCat.pdf[10-20] -profile eciCMYK.icc -profile eciRGB_v2.icc -quality 100 y-%04d.jpg</block></pre>



<p>I got this message:</p>



<pre class="wp-block-preformatted">convert: delegate library support not built-in `SaleCat.pdf' (LCMS) @ warning/profile.c/ProfileImage/565.</pre>



<p>I ran the following to see the delegates installed:</p>



<pre class="wp-block-preformatted">convert -list configure | grep -i "delegates"</pre>



<p>The results showed the lcms delegate wasn&#8217;t setup:</p>



<pre class="wp-block-preformatted">DELEGATES     bzlib fontconfig freetype gs jpeg jng jp2 lzma openexr pango png rsvg tiff x11 xml wmf zlib</pre>



<p>I verified that lcms was already installed with yum install lcms2 (it was).</p>



<p>So it appears that I needed to rebuild ImageMagick from source to include the lcms2 delegate.  I removed Image magic with &#8220;yum remove ImageMagick&#8221; first.</p>



<p>I made sure gcc was installed:</p>



<pre class="wp-block-preformatted">yum install gcc</pre>



<p>Then downloaded and configured the ImageMagick source:</p>



<pre class="wp-block-preformatted">wget https://imagemagick.org/download/ImageMagick.tar.gz<br>tar xvfz ImageMagick.tar.gz<br>cd ImageMagick-*<br>./configure  --with-lcms=yes</pre>



<p>The config should show that lcms was now enabled, but it wasn&#8217;t:</p>



<pre class="wp-block-preformatted">LCMS              --with-lcms=yes             <strong>no</strong></pre>



<p>So I looked at config.log to see the details:</p>



<pre class="wp-block-preformatted">     configure:31839: checking for lcms2 &gt;= 2.0.0<br>     configure:31846: $PKG_CONFIG --exists --print-errors "lcms2 &gt;= 2.0.0"<br>     Package lcms2 was not found in the pkg-config search path.<br>     Perhaps you should add the directory containing `lcms2.pc'<br>     to the PKG_CONFIG_PATH environment variable<br>     No package 'lcms2' found</pre>



<p>I made sure that lcms2 devel was installed:</p>



<pre class="wp-block-preformatted">yum install lcms2-devel</pre>



<p>I tried again to build:</p>



<pre class="wp-block-preformatted">./configure  --with-lcms=yes</pre>



<p><br> And this time the config looked good:</p>



<pre class="wp-block-preformatted">LCMS              --with-lcms=yes             <strong>yes</strong></pre>



<p>And so I built and installed ImageMagick from the source:</p>



<pre class="wp-block-preformatted">make<br>make install<br>make clean</pre>



<p>Now I can run convert from /usr/local/bin/convert and process with icc files.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>My Great ProxMox Experiment</title>
		<link>https://www.mariogiannini.com/2018/05/21/my-great-proxmox-experiment/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Mon, 21 May 2018 20:32:00 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.mariogiannini.com/?p=222</guid>

					<description><![CDATA[I have a Windows Server 2003 VM on VMWare ESXi, running SQL Server 2005 with a database that is split between E: and F: drives (the VM has 3 virtual disks). As a test for ProxMox 5.2, I wanted to convert this to a ProxMox VM, then increase the E: space to consolidate the data &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2018/05/21/my-great-proxmox-experiment/" class="more-link">Continue reading<span class="screen-reader-text"> "My Great ProxMox Experiment"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>I have a Windows Server 2003 VM on VMWare ESXi, running SQL Server 2005 with a database that is split between E: and F: drives (the VM has 3 virtual disks).  As a test for ProxMox 5.2, I wanted to convert this to a ProxMox VM, then increase the E: space to consolidate the data into a single drive and remove the F: drive.&nbsp; Long story short: Everything worked fine.</p>



<p>The following articles cover the details of the endeavor:</p>



<ul class="wp-block-list"><li><a href="http://www.mariogiannini.com/2018/05/20/copying-esxi-6-5-vm-to-proxmox-5-2/">Copying ESXi 6.5 VM to ProxMox 5.2</a></li><li><a href="http://www.mariogiannini.com/2018/05/19/increase-vm-disk-and-consolidate-sql-database/">Increase VM Disk and Consolidate SQL database</a></li></ul>



<p>Overall, ProxMox is a very slick product.&nbsp; I&#8217;ve used it on and off for various test home labs, and opted to use it at work on Lab computers that no longer support VMWare ESXi hosts.&nbsp; Installation was pretty painless, though understanding the various storage options got me a bit confused.&nbsp; </p>



<p>The worst problem I had with ProxMox was that the web-based Console used to access the VM wouldn&#8217;t work in IE 11.&nbsp; I thought there was some major issue as the web-based Console would never connect to the VM.&nbsp; But once I logged in with Chrome, I could access the VM perfectly fine through the exact same &#8216;console&#8217; option.</p>



<p>In one experiment, I did go for a high-availability with host-to-host cross replication and switch-over to a single host after powering down one of the hosts.&nbsp; After some trial and error I got things to work, but it&#8217;s not as smooth as VMWares replication features.</p>



<p><strong>Cost<br></strong>Both ProxMox and vSphere/ESXi are available for free.  ESXi free is a crippled version of the product, specifically in the area of templates, backups and High Availability features.  You can purchase a perpetual license of vSphere for approximately $5,654, which breaks down to about 4,470 for a perpetual license key, and 1,184 for 1 year of support which covers up to 3 hosts and 3 CPUs per host.  By comparison, the ProxMox free version primarily just comes with a nag screen at web login.  The ProxMox support subscription varies in price, but they charge between $796 and $74.90 per CPU and per host, which can wind up costing more than VMWare based on your needs.</p>



<p>For example, in the past year I have come to rely on VMWare’s support which has been excellent.  Based on the past year of VMWare support, we would need to purchase the $398 ProxMox subscription, which would cost $1,592 per year for our 3 hosts with 4 CPUs.  That’s $408 more than the VMWare support.</p>



<p><strong>Conclusion</strong><br>Both VMWare and ProxMox have handled the situations I threw at them.  Both have worked wonderfully, but both have experienced hiccups along the way.  None of those hiccups have required a complete system restore, only various changes in settings.  The trade-offs come in the form of high availability, backups, and support.  Converting a VM from ESXi to ProxMox was a painless endeavor.</p>



<p>Generally speaking, VMWare is the king of the virtualization land.  Its price is a bit steep for small organizations, but it may not be that far off from a similar ProxMox installation.  Relying on your own technical expertise can save you money.</p>



<p>If I were faced with a dirt-cheap scenario, I would probably go with a free ESXi setup and rely on open source backup software such as Macrium Reflect.  If there’s a second hardware host available, I would split the VMs between the 2 hosts, and using scheduled scripting to stop the VMs and cross-copy them between the 2 hosts.  Not exactly High Availability, but still workable in case of hardware failure.</p>



<p>Once a budget is introduced, I would still push for VMWare, despite the higher initial investment.  The assumption is that there are 2 host machines with cross-replication of VMs for  High Availability.  The VMWare support has been excellent in our production environment, and I have not used ProxMox support because we don’t have a subscription.</p>



<p>Note that if you are limited to older hardware, then ProxMox may be your only solution.  VMWare updates eventually stop supporting older processors. Hardware that works fine with ProxMox or an older VMWare installation may not be usable with a current version of VMWare..</p>



<p>Our solution is VMWare with production support running on 2 cross-replicated servers and all VMs copied to a disaster recovery server.  If 1 host physically dies, we can be back up and running in 5 minutes.  If 2 hosts die, it can take a few hours, but the disaster recovery machine can be brought online.  We also use ProxMox free on 2 lab servers.  They allow me to run several low-priority VMs and test VMs and test changes.</p>



<p> <strong>Update: Emergency Mode</strong> <br>After completing my experiment, I rebooted my ProxMox server after it had been running for more than 2 months.  Except, it kept booting into Emergency mode.  Networking was working as I could ping the host server, but not much else.</p>



<p>I went to the console, logged in and manually launched the sshd service, and was able to remote in from my desktop.  I then looked at <em>journalctl -xb </em>looking for red flags, and I found red/error reports regarding the tmp volume. </p>



<p>After further review, I found that I had created a logical volume and made a permanant mount line in etc/fstabs, but later removed the logical volume without removing the line from fstabs.  Trying to mount the non-existing logical volume was my cause.  Once I manually removed that line and rebooted, everything was back to normal.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Copying ESXi 6.5 VM to ProxMox 5.2</title>
		<link>https://www.mariogiannini.com/2018/05/20/copying-esxi-6-5-vm-to-proxmox-5-2/</link>
		
		<dc:creator><![CDATA[Mario]]></dc:creator>
		<pubDate>Sun, 20 May 2018 20:19:44 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">http://www.mariogiannini.com/?p=210</guid>

					<description><![CDATA[The steps outlined here were what I needed to do to convert a VMware ESXi 6.5 VM for use in a ProxMox 5.2 host.&#160; I wanted to test changing drive sizes and SQL database modifications without messing with a production server. Preparing the VM on VMWare ESXiRemove VMWare tools from the VM, through the VM &#8230; <p class="link-more"><a href="https://www.mariogiannini.com/2018/05/20/copying-esxi-6-5-vm-to-proxmox-5-2/" class="more-link">Continue reading<span class="screen-reader-text"> "Copying ESXi 6.5 VM to ProxMox 5.2"</span></a></p>]]></description>
										<content:encoded><![CDATA[
<p>The steps outlined here were what I needed to do to convert a VMware ESXi 6.5 VM for use in a ProxMox 5.2 host.&nbsp; I wanted to test changing drive sizes and SQL database modifications without messing with a production server.</p>



<p><strong>Preparing the VM on VMWare ESXi</strong><br>Remove VMWare tools from the VM, through the VM guest OS. <br><br>Download and run mergeide.zip from <a href="https://pve.proxmox.com/wiki/File:Mergeide.zip">https://pve.proxmox.com/wiki/File:Mergeide.zip</a><br><br>Make sure Atapi.sys, Intelide.sys, Pciide.sys, and Pciidex.sys are in the %SystemRoot%\System32\Drivers folder. If any are missing they can be extracted from %SystemRoot%\Driver Cache\I386\Driver.cab which can be opened in Windows file Exlorer like a directory and then the missing files can be copied out.<br><br>Shutdown the VM.</p>



<p><strong>Creating temporary space for the VMDK files on ProxMox host</strong><br>Because my VM totals about 300GB, I need to allocate enoughspace to store and convert the VMWare VMDK files.&nbsp; My default install of ProxMox left a 98GB ‘Directory’ type storage named ‘local’ (too small for this process) and a 5TB ‘LVM-Thin’ type storage named ‘local-lvm’.</p>



<p>Use lvcreate to create a new logical volume named tmp, 900GB in size, in the pre-existing pve volume group:</p>



<pre class="wp-block-preformatted">lvcreate -n tmp -L 900G pve</pre>



<p>Create a file structure on the logical volume:</p>



<pre class="wp-block-preformatted">mkfs.ext4 /dev/pve/tmp</pre>



<p>Add now mount the volume:</p>



<pre class="wp-block-preformatted">mkdir /var/lib/tmp<br>mount -t ext4 /dev/pve/tmp /var/lib/tmp<br></pre>



<p>Note: If you wanted to make tmp permanent, run the following:</p>



<pre class="wp-block-preformatted">echo '/dev/pve/tmp /var/lib/tmp ext4 defaults 0 2' &gt;&gt; /etc/fstab</pre>



<p><font style="color:red"><strong>NOTE</strong>:</font> I added the above line for a permanent mount, but then removed the logical volume without removing the line from fstab.  The result was that ProxMox then booted into Emergency mode until I removed that line).</p>



<p><strong>Create the new VM onProxMox</strong><br>We need to create a new VM with that has the same number of hard drives as the original VMWare VM, but each should have slightly more space allocated.&nbsp; Our VM started with 3 drives, 20, 165, and 200 GB in size, so we are going to create a ProxMox VM with 21, 166, and 201GB in size.</p>



<p>We opted for similar CPU settings and identical memorysettings for the ProxMox machine as from the VMWare VM.&nbsp; Once the initial VM was created with a 21GBdrive, we went back to the Hardware tab for the ProxMox VM and added the 166GB and 201GB hard drives.</p>



<p>Make note of your new VM’s ID number, it will be needed in
the next step.&nbsp; Our example will be 102.</p>



<p><strong>Copy and convert theVMDK files</strong><br>There were several options available to get the VMDK files.&nbsp; I could use pscp or FTP on my Windows workstation to copy files from the ESXi host to my PC and then again to copy to the ProxMox host.&nbsp; Instead, I opted to use the scp command on the ProxMox host to copy the files directly.&nbsp; Make sure that the VM is powered down and snapshots are consolidated before copying.</p>



<pre class="wp-block-preformatted">scp root@ESX1:/vmfs/volumes/518eblah-a4bablah-blah-69ee0a22blah/Anakin/*-flat.vmdk
/var/lib/tmp</pre>



<p>Now, with all our VMDK files, we want to convert them into the virtual disks that were created with our new ProxMox VM.&nbsp; If you list the files in /dev/pve, you should see the virtual disk files (again, our demo uses VM ID 102):</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="568" height="34" src="http://www.mariogiannini.com/wp-content/uploads/2018/12/convert2018.png" alt="" class="wp-image-212" srcset="https://www.mariogiannini.com/wp-content/uploads/2018/12/convert2018.png 568w, https://www.mariogiannini.com/wp-content/uploads/2018/12/convert2018-300x18.png 300w" sizes="auto, (max-width: 568px) 100vw, 568px" /></figure>



<p>Using the qemu-img tool on the ProxMox host, we will convert the VMDK into a raw file format, and store it directly into the virtual disks already created for the ProxMox VM (once for each virtual disk).&nbsp; Note that this can take some time for large virtual disks:</p>



<pre class="wp-block-preformatted">root@lab2:/#qemu-img convert /var/lib/tmp/ANAKIN-flat.vmdk -O raw /dev/pve/vm-102-disk-0<br>root@lab2:/#qemu-img convert /var/lib/tmp/ANAKIN_1-flat.vmdk -O raw /dev/pve/vm-102-disk-1<br>root@lab2:/#qemu-img convert /var/lib/tmp/ANAKIN_2-flat.vmdk -O raw /dev/pve/vm-102-disk-2<br><br></pre>



<p>That&#8217;s it.&nbsp; You should now be able to start the VM on the ProxMox host.</p>



<p><strong>Removing Temporary storage</strong><br>When done, we can remove the temporary storage we created.</p>



<p>Unmount it and then remove it with the following:</p>



<pre class="wp-block-preformatted">umount /var/lib/tmp<br>lvremove pve/tmp</pre>



<p>Make sure that you remove any entries in etc/fstab if you added them for permanent mounting of the logical volume.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
