<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Puppeteers on Puppeteers Oy</title>
		<link>https://www.puppeteers.net/</link>
		<description>Recent content in Puppeteers on Puppeteers Oy</description>
		<generator>Hugo</generator>
		<language>en-US</language>
		
		
		
		
			<lastBuildDate>Mon, 02 Dec 2024 00:00:00 +0000</lastBuildDate>
		
			<atom:link href="https://www.puppeteers.net/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>Customer testimonials</title>
				<link>https://www.puppeteers.net/references/customer-testimonials/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/customer-testimonials/</guid>
				<description>What do customers say about Puppeteers?</description>
			</item>
			<item>
				<title>Case: event-driven automation with Kafka and Ansible</title>
				<link>https://www.puppeteers.net/references/case-event-driven-automation-with-kafka-and-ansible/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-event-driven-automation-with-kafka-and-ansible/</guid>
				<description>Case: event-driven automation with Kafka and Ansible</description>
			</item>
			<item>
				<title>DevOps partner service</title>
				<link>https://www.puppeteers.net/products/devops-partner-service/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/products/devops-partner-service/</guid>
				<description>You can get an experienced DevOps team working for you, with you,e on call when you need us.</description>
			</item>
			<item>
				<title>Samuli Seppänen</title>
				<link>https://www.puppeteers.net/who-we-are/samuli-seppanen/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/who-we-are/samuli-seppanen/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/cropped-puppeteers_WP-user-Samuli.jpg&#34; alt=&#34;Samuli Seppänen&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Samuli is our CEO and “puppet master”. Samuli has worked with computers since&#xA;early 1980&amp;rsquo;s, moving from the Sinclair Spectrum to MSX to Amiga and from there&#xA;to the PC. In 1998 he installed Linux to his PC. Samuli did an MA in archeology&#xA;but decided to follow another passion of his, IT.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Freetime interests:&lt;/strong&gt; Shooting, working and studying languages.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Fun fact:&lt;/strong&gt; Rarely, when time permits, Samuli spends time recreating ancient&#xA;weapons such as crossbows and cheiroballistas.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Case: SaaS Cloud backend automation</title>
				<link>https://www.puppeteers.net/references/case-saas-cloud-backend-automation/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-saas-cloud-backend-automation/</guid>
				<description>Case: SaaS Cloud backend automation</description>
			</item>
			<item>
				<title>LibreNMS image</title>
				<link>https://www.puppeteers.net/products/librenms-image/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/products/librenms-image/</guid>
				<description>The fastest and easiest way to get going with LibreNMS</description>
			</item>
			<item>
				<title>Petri Lammi</title>
				<link>https://www.puppeteers.net/who-we-are/petri-lammi/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/who-we-are/petri-lammi/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/cropped-puppeteers_WP-user-Petri.jpg&#34; alt=&#34;Petri Lammi&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Petri&amp;rsquo;s first computer was an IBM AT which he took apart dozens of times in&#xA;order to understand what makes it tick. During his studies in philosophy he&#xA;transitioned from DOS/Windows to Linux and a world of new possibilities opened&#xA;up to him. This made him get to his senses and acquire a “real” career in ICT.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Favourite thing about IT:&lt;/strong&gt; Prototyping and learning new technologies.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Favourite food:&lt;/strong&gt; Anything that doesn&amp;rsquo;t contain carbs.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Case: Ansible Automation Platform deployment</title>
				<link>https://www.puppeteers.net/references/case-ansible-automation-platform-deployment/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-ansible-automation-platform-deployment/</guid>
				<description>Case: Ansible Automation Platform deployment</description>
			</item>
			<item>
				<title>Case: containerized Buildbot CI/CD system</title>
				<link>https://www.puppeteers.net/references/case-containerized-buildbot-cicd-system/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-containerized-buildbot-cicd-system/</guid>
				<description>Case: containerized Buildbot CI/CD system</description>
			</item>
			<item>
				<title>Netbox image</title>
				<link>https://www.puppeteers.net/products/netbox-image/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/products/netbox-image/</guid>
				<description>The fastest and easiest way to get going with Netbox</description>
			</item>
			<item>
				<title>Ricky Cousins</title>
				<link>https://www.puppeteers.net/who-we-are/ricky-cousins/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/who-we-are/ricky-cousins/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/cropped-puppeteers_WP-user-Ricky.jpg&#34; alt=&#34;Ricky Cousins&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Ricky is an autodidact who loves problem-solving and learning new tools and&#xA;techniques. He is originally from Tulsa, Oklahoma (US).&lt;/p&gt;&#xA;&lt;p&gt;Ricky started his career in IT with taking apart his computer when he was a&#xA;young kid. His curiosity led him to Linux which sparked a passion. In the&#xA;process of learning more about computers, he found himself quite useful to his&#xA;friends and neighbors. He enjoys automating and tinkering and often loses track&#xA;of time doing so.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Case: Keycloak domain mode cluster</title>
				<link>https://www.puppeteers.net/references/case-keycloak-domain-mode-cluster/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-keycloak-domain-mode-cluster/</guid>
				<description>Case: Keycloak domain mode cluster</description>
			</item>
			<item>
				<title>Case: Linux HPC cluster automation</title>
				<link>https://www.puppeteers.net/references/case-linux-hpc-cluster-automation/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-linux-hpc-cluster-automation/</guid>
				<description>Case: Linux HPC cluster automation</description>
			</item>
			<item>
				<title>Case: Windows software robot automation project</title>
				<link>https://www.puppeteers.net/references/case-windows-software-robot-automation-project/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-windows-software-robot-automation-project/</guid>
				<description>Case: Windows software robot automation project</description>
			</item>
			<item>
				<title>Case: Jenkins configuration automation</title>
				<link>https://www.puppeteers.net/references/case-jenkins-configuration-automation/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/references/case-jenkins-configuration-automation/</guid>
				<description>Case: Jenkins configuration automation</description>
			</item>
			<item>
				<title>Getting latest Rocky Linux AMI ID</title>
				<link>https://www.puppeteers.net/blog/getting-latest-rocky-linux-ami-id/</link>
				<pubDate>Mon, 02 Dec 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/getting-latest-rocky-linux-ami-id/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-timmossholder-1934895.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://rockylinux.org/&#34;&gt;Rocky Linux&lt;/a&gt; 9 is a bug-by-bug clone of &lt;a href=&#34;https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux&#34;&gt;Red Hat Enterprise Linux&lt;/a&gt; 9 (RHEL 9). We generally recommend using RHEL 9 for mission-critical workloads, but for less important services Rocky Linux 9 is a very good choice if you&amp;rsquo;re in the Red Hat land already. Official Rocky images are only available in AWS Marketplace, which complicates things when you need to programmatically determine the latest version. This is a common requirement when you do &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt;, for example with Ansible, &lt;a href=&#34;https://www.puppeteers.net/learn/what-is-terraform-and-how-does-it-work/&#34;&gt;Terraform&lt;/a&gt; or Packer. Although we speak of latest Rocky Linux AMI here, everything in here is applicable for any other AWS Marketplace images, for example Alma Linux.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Fixing ansible-playbook hangs caused by SSH timeouts</title>
				<link>https://www.puppeteers.net/blog/fixing-ansible-playbook-hangs-caused-by-ssh-timeouts/</link>
				<pubDate>Fri, 29 Nov 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fixing-ansible-playbook-hangs-caused-by-ssh-timeouts/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-brent-mcquery-531366837-22300915.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.ansible.com/&#34;&gt;Ansible&lt;/a&gt; is an &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt; tool that uses SSH as its transport mechanism. When the targeted nodes are close, latency-vise to the Ansible controller things usually work fine with the default settings. However, when the targets are far away or latency is big, you may notice that ansible-playbook hangs on some long-running task and never recovers. When you rerun the playbook it may proceed further and then hang at some other task. Or the same task. This is incredibly frustrating, but fortunately also fairly easy to fix.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Monitoring Azure with Prometheus</title>
				<link>https://www.puppeteers.net/blog/monitoring-azure-with-prometheus/</link>
				<pubDate>Thu, 31 Oct 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/monitoring-azure-with-prometheus/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-kelly-2543201-trimmed-1.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://prometheus.io/&#34;&gt;Prometheus&lt;/a&gt; is a great tool for &amp;ldquo;cloud-native&amp;rdquo; metrics gathering and monitoring. It is particularly easy to manage with &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt; methods. Prometheus can collect metrics from various sources, including &lt;a href=&#34;https://azure.microsoft.com/en-us/products/monitor/&#34;&gt;Azure Monitor&lt;/a&gt;. You can use &lt;a href=&#34;https://github.com/webdevops/azure-metrics-exporter&#34;&gt;Azure Metrics Exporter&lt;/a&gt; to convert Azure Monitor metrics into Prometheus metrics, but doing so is definitely not trivial unless you&amp;rsquo;re pretty familiar with Prometheus, Azure Monitor and Microsoft Entra ID apps. This article tries to help you make monitoring Azure with Prometheus a breeze instead of a struggle. We won&amp;rsquo;t go into a lot of detail about Prometheus or Azure Monitor as there&amp;rsquo;s plenty of information available elsewhere about both of them. Also note that this article is about vanilla Prometheus, &lt;em&gt;not&lt;/em&gt; Microsoft&amp;rsquo;s &amp;ldquo;Azure Monitor managed service for Prometheus&amp;rdquo;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Avoid double taxation when selling to the U.S</title>
				<link>https://www.puppeteers.net/blog/avoid-double-taxation-when-selling-to-the-u-s/</link>
				<pubDate>Thu, 03 Oct 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/avoid-double-taxation-when-selling-to-the-u-s/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-karolina-grabowska-4386367.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;We sell digital products in &lt;a href=&#34;https://aws.amazon.com/marketplace/&#34;&gt;AWS Marketplace&lt;/a&gt;, &lt;a href=&#34;https://azuremarketplace.microsoft.com&#34;&gt;Azure Marketplace&lt;/a&gt; and &lt;a href=&#34;https://www.udemy.com/&#34;&gt;Udemy&lt;/a&gt; - see our &lt;a href=&#34;https://www.puppeteers.net/products/&#34;&gt;products page&lt;/a&gt; for detail. The end customers of our products are located around the world, including the Unites States of America. All the aforementioned platforms a located in the U.S. This means that they comply with the U.S. tax laws both on the state and federal level. &lt;a href=&#34;https://www.irs.gov/&#34;&gt;Internal Revenue Service&lt;/a&gt; (IRS) is responsible for collecting the federal taxes, which are relevant for this article. Foreign (e.g. European) corporations that sell (digital) products or services to U.S. customers need to prove to IRS that it should not withhold federal taxes from the income coming from U.S. end customers. The goal of this article is to help European corporations (companies) avoid double taxation: first by the IRS and then by the tax office of its own home country. We have all the basic information that a typical European corporation (company) needs to do to avoid double taxation when selling services or digital products to U.S. end customers.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Alldomains.hosting IPv6 support</title>
				<link>https://www.puppeteers.net/blog/alldomains-hosting-ipv6-support/</link>
				<pubDate>Wed, 25 Sep 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/alldomains-hosting-ipv6-support/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-maksgelatin-5605061.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;ve recently started using &lt;a href=&#34;https://alldomains.hosting/en/index.html&#34;&gt;alldomains.hosting&lt;/a&gt; for what we call &amp;ldquo;programmatic emails&amp;rdquo;. For that purpose alldomains.hosting is dirt cheap (~1€/year/email address), which makes one quite motivated to suffer through the confusing website to figure out how to buy stuff from them. Once you&amp;rsquo;ve managed to buy your domain and/or mail services they just &amp;ldquo;tend to work&amp;rdquo;. Alldomains.hosting IPv6 support, or lack of it, may be a problem for you, though.&lt;/p&gt;&#xA;&lt;p&gt;For example, in AWS EC2 you nowadays really want to avoid assigning public IPv4 addresses to EC2 instances as they cost quite a lot. So, you set up an IPv6-only egress-only internet gateway in your VPC and, for the most part, everything &amp;ldquo;just works&amp;rdquo;. Then you try to add mail delivery via alldomains.hosting and IPv6 and &amp;ldquo;boom&amp;rdquo;, it does not work. According to their support (as of 25.9.2024) their mail servers lack IPv6 support.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Microsoft Entra ID multi-factor authentication in RDP</title>
				<link>https://www.puppeteers.net/blog/microsoft-entra-id-multi-factor-authentication-in-rdp/</link>
				<pubDate>Fri, 28 Jun 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/microsoft-entra-id-multi-factor-authentication-in-rdp/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-olly-3760043.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Microsoft Entra ID, formerly known as Azure Activate Directory (AAD), is replacing classic on-premise Active Directory installations slowly but surely. It replaces &amp;ldquo;legacy&amp;rdquo; protocols such as LDAP and Kerberos with &amp;ldquo;modern&amp;rdquo; protocols such as SAML, OIDC and OAuth2. However, the client-side support in various operating systems such as Windows, Linux and MacOS is spotty, to say the least. You can make things work, but only if the stars (or rather, bits) are aligned &lt;em&gt;just right&lt;/em&gt;. This article explains how multi-factor authentication in RDP works with Azure VMs when using Microsoft Entra ID. Note the emphasis on &lt;strong&gt;MFA&lt;/strong&gt;: without MFA you can make logins with Entra ID work more easily by using the normal username + password authentication in RDP.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Installing OpenBSD 7.5 with virt-install on Linux</title>
				<link>https://www.puppeteers.net/blog/installing-openbsd-7-5-with-virt-install-on-linux/</link>
				<pubDate>Wed, 12 Jun 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/installing-openbsd-7-5-with-virt-install-on-linux/</guid>
				<description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.openbsd.org/&#34;&gt;OpenBSD&lt;/a&gt; 7.5 is a UNIX-like operating system. The project&amp;rsquo;s &amp;ldquo;efforts emphasize portability, standardization, correctness, proactive security and integrated cryptography&amp;rdquo;. Compared to modern Linux distributions OpenBSD is &lt;em&gt;very&lt;/em&gt; compact, but comes with the usual packages and ports tree you would expect from any *BSD operating system. This article shows the process of installing OpenBSD 7.5 with virt-install, making it a virtualization guest on Linux.&lt;/p&gt;&#xA;&lt;h2 id=&#34;downloading-the-iso-installer&#34;&gt;Downloading the ISO installer&lt;/h2&gt;&#xA;&lt;p&gt;First you need to download the OpenBSD 7.5 ISO installer on your Linux system. On most systems the amd64 &lt;a href=&#34;https://cdn.openbsd.org/pub/OpenBSD/7.5/amd64/install75.iso&#34;&gt;install75.iso&lt;/a&gt; is the correct choice. Check the OpenBSD &lt;a href=&#34;https://www.openbsd.org/faq/faq4.html#Download&#34;&gt;download page&lt;/a&gt; for other architectures.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using Hiera with Ansible</title>
				<link>https://www.puppeteers.net/blog/using-hiera-with-ansible/</link>
				<pubDate>Fri, 07 Jun 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-hiera-with-ansible/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-skitterphoto-63901.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.puppet.com/docs/puppet/8/hiera.html&#34;&gt;Hiera&lt;/a&gt; is a very powerful &amp;ldquo;key-value configuration data lookup system&amp;rdquo; used mainly, but not exclusively, with the &lt;a href=&#34;https://www.puppeteers.net/learn/what-is-puppet-and-how-does-it-work/&#34;&gt;Puppet&lt;/a&gt; configuration management and orchestration system. In Hiera data is stored in in yaml files in, as the name implies, a hierarchy or set of prioritized &lt;em&gt;levels&lt;/em&gt;. A typical Hiera lookup goes through the hierarchy starting from the highest-priority level and stops when it finds a match. That match could come from a node yaml file, a deployment (e.g. production or staging) yaml file or from site-wide yaml. What this essentially means is that you can define common, site-wide parameters at the lowest level of the hierarchy and override those when needed at higher levels. How does Hiera and Ansible work together, then? The short answer is &amp;ldquo;they don&amp;rsquo;t, really&amp;rdquo;, but the long answer is more complex than that.&lt;/p&gt;</description>
			</item>
			<item>
				<title>RHEL on Upcloud</title>
				<link>https://www.puppeteers.net/blog/rhel-on-upcloud/</link>
				<pubDate>Mon, 27 May 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/rhel-on-upcloud/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-pixabay-86695.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://upcloud.com/&#34;&gt;Upcloud&lt;/a&gt; is a Finnish Cloud provider that focuses on high-quality services. There is no built-in support for installing RHEL on Upcloud, which is quite typical of &amp;ldquo;small Clouds&amp;rdquo;. Sometimes you don&amp;rsquo;t want to use clones (e.g. Rocky Linux) and need real RHEL instead. This is where this article comes handy, as the RHEL installation process in Upcloud is far from trivial. This article focuses on RHEL 9, but the process may work with older and newer versions as well. The process I describe here applies almost 1:1 to &lt;em&gt;any&lt;/em&gt; Linux operating system Upcloud does not natively support.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Buildbot build order: how to run certain builds before others?</title>
				<link>https://www.puppeteers.net/blog/buildbot-build-order-how-to-run-certain-builds-before-others/</link>
				<pubDate>Tue, 06 Feb 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/buildbot-build-order-how-to-run-certain-builds-before-others/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Buildbot-DependentScheler-in-action.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;The mechanisms for configuring Buildbot build order is documented fairly well. However, what that documentation lacks is a centralized place where ordering is explained. My personal goal was to run smoke tests first and if those don&amp;rsquo;t pass then cancel all other build requests. That seemed straightforward, but turned out not to be so. There were many, many ways that could in theory be achieved, but most of those did not work at all, or worked only partially. This article attempts to fill the &amp;ldquo;how do I order builds in Buildbot&amp;rdquo; gap, including what can and can&amp;rsquo;t be achieved with each strategy.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Red Hat subscriptions quick start</title>
				<link>https://www.puppeteers.net/blog/red-hat-subscriptions-quick-start/</link>
				<pubDate>Mon, 15 Jan 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/red-hat-subscriptions-quick-start/</guid>
				<description>&lt;p&gt;What follows is an minimalistic, bare-bones guide to get you started with Red Hat subscriptions quickly. No spoon-feeding, no introductions, just get your first RHEL* system into a blessed state quickly, while your attention can still keep up. &lt;/p&gt;&#xA;&lt;p&gt;We assume you are starting from scratch and generally have no glue. We also assume that your boss has punished you with this task, not your mom, and therefore you represent a company, not a Sapiens specimen that looks like you. If this is not the case, then it isn&amp;rsquo;t.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Stop EC2 instances automatically with Terraform</title>
				<link>https://www.puppeteers.net/blog/stop-ec2-instances-automatically-with-terraform/</link>
				<pubDate>Thu, 04 Jan 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/stop-ec2-instances-automatically-with-terraform/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-mikhail-nilov-7663143.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;AWS EC2 is a very convenient place for experimenting with and testing things on virtual machines (or &amp;ldquo;EC2 instances&amp;rdquo;). However, it is also very easy to forget such EC2 instances running for no reason, which can become very costly very quickly. Fortunately In AWS computing (e.g. CPU, memory and I/O usage) and storage (disk) usage are billed separately. In other words: if your EC2 instance is stopped, you only pay for its storage. This cuts down the costs &lt;em&gt;significantly&lt;/em&gt;, especially if your are using powerful EC2 instance types. So, you definitely should to stop EC2 instances automatically, say, every evening, if you don&amp;rsquo;t need them to be up. There is no built-in way in to do, though, so this article shows a couple ways it can be done.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Understanding Infrastructure as Code (IaC)</title>
				<link>https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/</link>
				<pubDate>Tue, 02 Jan 2024 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/</guid>
				<description>Learn what infrastructure as code is and how you can utilize it to your advantage</description>
			</item>
			<item>
				<title>Options for building self-service infrastructure with Ansible and Terraform</title>
				<link>https://www.puppeteers.net/blog/options-for-building-self-service-infrastructure-with-ansible-and-terraform/</link>
				<pubDate>Wed, 22 Nov 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/options-for-building-self-service-infrastructure-with-ansible-and-terraform/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-esranur-kalay-12259336-1-768x1024.jpg&#34; alt=&#34;It is possible to build self-service infrastructure with Ansible and Terraform&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Being able to build IT infrastructure always having to involve an IT, operations or platform team seems be a big priority for many organizations. This is understandable because processes typically slow down to a crawl when they have to pass organizational boundaries. Also, teams responsible for infrastructure would not want to spend time on routine requests if possible. Provisioning infrastructure is no exception here. It is possible to create a custom solution to enable self-service infrastructure with Ansible and Terraform, but that takes a fair amount of effort. In this article we focus on open source and commercial open source offerings that make enabling self-service infrastructure provisioning easier.&lt;/p&gt;</description>
			</item>
			<item>
				<title>COSS-webinaari: automaatio avoimen lähdekoodin välinein</title>
				<link>https://www.puppeteers.net/blog/coss-webinaari-automaatio-avoin-lahdekoodi/</link>
				<pubDate>Mon, 20 Nov 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/coss-webinaari-automaatio-avoin-lahdekoodi/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Kuvakaappaus-2023-11-20-10-26-49.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Toimitusjohtajamme &lt;strong&gt;Samuli Seppänen&lt;/strong&gt; on kutsuttu puhujaksi &lt;strong&gt;COSS ry&lt;/strong&gt;:n webinaariin ma 4.12. 2023 klo 9. Webinaarin aiheena avoimen lähdekootin välinein toteutettava IT-automaatio.&lt;/p&gt;&#xA;&lt;p&gt;&amp;ldquo;IT-automaatiolla nostetaan kierroksia samalla kun vähennetään kaasua. Avoimen lähdekoodin välinein tehdyllä IT-automaatiolla voidaan nopeuttaa ja tehostaa toimintaa sekä parantaa työn tuloksia mitattavasti. Yrityksille ja organisaatioille, joiden on pakko hakea yhä uusia keinoja kilpailukykynsä parantamiseen, IT-automaatio antaa syvällisesti toteutettuna mukavan lisäpotkun kilpailijoista erottautumiseen laadulla ja nopeudella. Strategisella automaatiolla voidaan lisäksi vähentää organisaation siiloutumista ja poistaa prosessien pullonkauloja. Mitä sitten avoimen lähdekoodin IT-automaatiosta tulisi tietää, jotta yritykset ja organisaatiot voivat valjastaa sen keskeiseksi osaksi tehokkuuden ja laadun maksimointia?&amp;rdquo;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Red Hat -automaatiolounas 1.11.2023</title>
				<link>https://www.puppeteers.net/blog/red-hat-automaatiolounas-1-11-2023/</link>
				<pubDate>Tue, 24 Oct 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/red-hat-automaatiolounas-1-11-2023/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Red-Hat-automaatiolounas.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Järjestämme yhteisen lounastapahtuman &lt;a href=&#34;https://www.redhat.com/en&#34;&gt;Red Hat&lt;/a&gt;in ja &lt;a href=&#34;https://6gnordic.com/&#34;&gt;6G Nordic Oy&lt;/a&gt;n kanssa Turussa 1.11.2023. Tapahtuma kulkee nimellä automaatiolounas ja siellä kuullaan käytännön esimerkkejä ja ajatuksia IT-automaatiosta ja siitä, miten se kannattaa valjastaa koko yrityksen käyttöön strategiseksi voimavaraksi. Tilaisuus on tarkoitettu tekijöille, tiiminvetäjille ja managereille - kaikille, jotka näkevät, että automaatiotason nostosta olisi hyötyä.&lt;/p&gt;&#xA;&lt;p&gt;Lämpimästä tervetuloa!&lt;/p&gt;&#xA;&lt;p&gt;Lisätietoja ja ilmoittautumiset &lt;a href=&#34;https://events.redhat.com/profile/form/index.cfm?PKformID=0x8666290001&#34;&gt;tästä&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Install RHEL 9 on Hetzner Cloud</title>
				<link>https://www.puppeteers.net/blog/install-rhel-9-on-hetzner-cloud/</link>
				<pubDate>Fri, 20 Oct 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/install-rhel-9-on-hetzner-cloud/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-mateusz-salaciak-4275885-1024x682.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Scaling a mountain is about as easy as to install RHEL 9 in Hetzner Cloud in scalable way. At minimum, you need this article and lots of endurance to pull it off. &lt;a href=&#34;https://www.pexels.com/it-it/foto/casa-in-legno-marrone-sul-campo-di-erba-verde-vicino-a-montagne-e-alberi-verdi-4275885/&#34;&gt;Photo credit&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.hetzner.com/cloud&#34;&gt;Hetzner Cloud&lt;/a&gt; is a really good &amp;ldquo;small&amp;rdquo; Cloud with particularly good value for money. While it does not have hundreds of services like AWS or Azure, but it has most of the basic stuff. Hetzner cloud has built-in support for Red Hat Enterprise Linux (RHEL) clones such as Rocky Linux 9. However, you &lt;em&gt;cannot&lt;/em&gt; spin up real RHEL 9 instances without spending some time on it. This article will give you all the details you need to install RHEL 9 on Hetzner Cloud. We do that in a way that you can reuse your RHEL 9 installation to spin up multiple servers from one snapshot. This way you don&amp;rsquo;t have to run the RHEL installer for every RHEL server you want to spin up.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppeteers Joins Red Hat Solution Provider Program</title>
				<link>https://www.puppeteers.net/blog/puppeteers-joins-red-hat-solution-provider-program/</link>
				<pubDate>Tue, 17 Oct 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppeteers-joins-red-hat-solution-provider-program/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Logo-Red_Hat-Ready-Business_Partner-Solution_Provider-A-Standard-CMYK-1024x749.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Puppeteers has started a collaboration with Red Hat, the world’s leading provider of open source solutions. This collaboration marks Puppeteers as a member of the Red Hat partner ecosystem, where it brings its expertise in automation and open-source technologies to the forefront.&lt;/p&gt;&#xA;&lt;p&gt;Today, organizations across various sectors are under immense pressure to deliver services quickly while upholding stringent security practices. Information technology is pivotal in meeting these demands, and automation offers a compelling solution to address challenges related to scalability, predictability, and efficiency. Red Hat, renowned for its automation solutions, is at the forefront of helping organizations navigate these challenges.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Blackbox Exporter ICMP module and selinux</title>
				<link>https://www.puppeteers.net/blog/blackbox-exporter-icmp-module-and-selinux/</link>
				<pubDate>Thu, 21 Sep 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/blackbox-exporter-icmp-module-and-selinux/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-pixabay-2748861-1024x682.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Blackbox Exporter ICMP module and selinux do not like each other. Same goes for systemd units and ICMP Echo sockets. However, with persistence, skill and a bit of luck you can make it all work together. &lt;a href=&#34;https://www.pexels.com/it-it/foto/foto-in-scala-di-grigi-del-filo-spinato-274886/&#34;&gt;Photo credit&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/prometheus/blackbox_exporter&#34;&gt;Blackbox Exporter&lt;/a&gt; is an exporter for the &lt;a href=&#34;https://prometheus.io/&#34;&gt;Prometheus&lt;/a&gt; monitoring system. It is able to probe a target, such as a host or an application from the outside. Blackbox Exporter does probing with modules such as http, tcp, dns, icmp and grpc (details &lt;a href=&#34;https://github.com/prometheus/blackbox_exporter/blob/master/CONFIGURATION.md&#34;&gt;here&lt;/a&gt;). The icmp module is special because it does privileged operations that require the CAP_NET_RAW capability and as well as custom selinux policies. This article aims to explain how you can make Blackbox Exporter ICMP module and selinux work together. &lt;strong&gt;NOTE:&lt;/strong&gt; you do not need any of these tricks if you use non-icmp Blackbox exporter modules.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Excluding down targets in Prometheus</title>
				<link>https://www.puppeteers.net/blog/excluding-down-targets-in-prometheus/</link>
				<pubDate>Fri, 11 Aug 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/excluding-down-targets-in-prometheus/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-kelly-2543201-trimmed-1-1021x1024.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Excluding down targets in Prometheus is easy. It allow you to monitor volatile systems that start and shut down on demand.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://prometheus.io/&#34;&gt;Prometheus&lt;/a&gt; is an open source metrics and alerting solution used to monitor a wide range of things. Unlike many classic network monitoring systems Prometheus is focused on colleting metrics. This makes it quite easy to do things that would be difficult in others systems. For example excluding down targets in Prometheus is quite trivial. This can be highly useful when you have volatile, static targets that come and go - for example Jenkins slaves (or build agents). Even on such targets you&amp;rsquo;d want to monitor things like systemd service status, memory usage and disk usage.&lt;/p&gt;</description>
			</item>
			<item>
				<title>How to reduce RDS storage size in an automated way</title>
				<link>https://www.puppeteers.net/blog/how-to-reduce-rds-storage-size-in-an-automated-way/</link>
				<pubDate>Thu, 10 Aug 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/how-to-reduce-rds-storage-size-in-an-automated-way/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-jakub-zerdzicki-16978372.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Amazon RDS is a relational database service available on Amazon Web Services. It is essentially a managed database server with a volume for the data. Both cost money. Having a large dataset is not the only reason have big volume: the volume size determines the number of I/O operations (IOPS) the volume can do. If you have high load on your RDS instance you may very well run out of IOPS which can result in a disaster. Scaling up the volume size is easy to avoid such disasters, but it is much more difficult to reduce RDS storage size. This is because downsizing RDS storage size &lt;a href=&#34;https://repost.aws/knowledge-center/rds-db-storage-size&#34;&gt;is not officially supported by AWS&lt;/a&gt;. If the load on your RDS instance goes down (e.g. due to refactoring), you may end up having a database with an oversized volume that costs lots of money for no reason.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Downsize AWS RDS Volume</title>
				<link>https://www.puppeteers.net/blog/downsize-aws-rds-volume/</link>
				<pubDate>Mon, 08 May 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/downsize-aws-rds-volume/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-pixabay-359641.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;It is trivial to downsize an AWS RDS &lt;em&gt;instance&lt;/em&gt;. It is equally trivial to upsize AWS RDS volumes. However, to downsize AWS RDS volume you need to jump through lots of hoops.&lt;/p&gt;&#xA;&lt;p&gt;So, why would you ever want to downsize an AWS RDS volume? One reason might be that you increased the volume size simply to get more burst credits for the &lt;em&gt;volume&lt;/em&gt;. Then you did refactoring that reduced the need to have that many credits and want to save money. Or maybe you genuinely had a huge amount of data on your RDS instance volume, removed some of it but got stuck with a huge volume.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Linux Azure AD authentication options</title>
				<link>https://www.puppeteers.net/blog/linux-azure-ad-authentication-options/</link>
				<pubDate>Wed, 26 Apr 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/linux-azure-ad-authentication-options/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/bash-gb216ea79b_640.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;There are a myriad of ways to login to Linux systems using Azure AD credentials. &lt;a href=&#34;https://pixabay.com/vectors/bash-command-line-linux-shell-148836/&#34;&gt;Photo credit&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;There are several ways to do Linux Azure AD authentication. Note that Azure AD was renamed &amp;ldquo;Microsoft Entra ID&amp;rdquo; recently, but in this article we&amp;rsquo;ll use its old name, at least for now. In other words you can log in to your Linux hosts &lt;a href=&#34;https://azure.microsoft.com/en-ca/products/active-directory/&#34;&gt;Azure Active Directory&lt;/a&gt; (&amp;ldquo;Azure AD&amp;rdquo;) credentials in various ways. &lt;a href=&#34;https://azure.microsoft.com&#34;&gt;Azure&lt;/a&gt;, Microsoft&amp;rsquo;s public Cloud, builds on top of Azure AD. In fact, your Azure users, groups, roles and role assignments are stored in Azure AD.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Keycloak Javascript policy deployment</title>
				<link>https://www.puppeteers.net/blog/keycloak-javascript-policy-deployment/</link>
				<pubDate>Wed, 19 Apr 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/keycloak-javascript-policy-deployment/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-serinus-5149241.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;This article tries to include &lt;em&gt;everything&lt;/em&gt; you need to know about Keycloak Javascript policy deployment. By Javascript policies I mean authorization policies of Javascript type attached to Keycloak clients that have authorization enabled. If you don&amp;rsquo;t know what Keycloak &lt;a href=&#34;https://www.puppeteers.net/blog/keycloak-authorization-services-terminology/&#34;&gt;authorization services&lt;/a&gt; are, you are probably in the wrong place.&lt;/p&gt;&#xA;&lt;p&gt;While the process of creating and deploying the JAR files is pretty well documented, it is not altogether clear for the uninitiated how the policies are shown in Keycloak.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Openshift versions: all you hopefully need to know</title>
				<link>https://www.puppeteers.net/blog/openshift-versions-all-you-hopefully-need-to-know/</link>
				<pubDate>Wed, 05 Apr 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/openshift-versions-all-you-hopefully-need-to-know/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-cottonbro-studio-7569424.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Red Hat Openshift is essentially an opinionated Kubernetes distribution that comes with a large number of features such as CI/CD and container registry built-in; for a full list of differences look at the &lt;a href=&#34;https://www.redhat.com/en/technologies/cloud-computing/openshift/red-hat-openshift-kubernetes&#34;&gt;Red Hat OpenShift vs. Kubernetes&lt;/a&gt;. Openshift comes in a number of versions, some commercial and some open source. The naming history of Openshift is &lt;em&gt;particularly&lt;/em&gt; confusing. That&amp;rsquo;s why I wrote this blog post where I attempt to list &lt;em&gt;most&lt;/em&gt; Openshift versions and variants and outline their main differences.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Keycloak authorization services REST API: paths and payloads</title>
				<link>https://www.puppeteers.net/blog/keycloak-authorization-services-rest-api-paths-and-payload/</link>
				<pubDate>Fri, 24 Mar 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/keycloak-authorization-services-rest-api-paths-and-payload/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-alex-andrews-12038081.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://www.keycloak.org/docs/latest/authorization_services/index.html&#34;&gt;Keycloak Authorization Services&lt;/a&gt; allows you to offload your application&amp;rsquo;s authorization decisions to Keycloak instead of implementing them in your code. This way you can leverage Keycloak&amp;rsquo;s advanced features like 2FA without any additional development on your part. If you&amp;rsquo;re unfamiliar with the Authorization Services I suggest having a look at the &lt;a href=&#34;https://www.puppeteers.net/blog/keycloak-authorization-services-terminology/&#34;&gt;Keycloak authorization services terminology&lt;/a&gt; first. You may also be interested in &lt;a href=&#34;https://www.puppeteers.net/blog/adding-new-permission-to-shared-resources-with-keycloak-rest-api/&#34;&gt;our sample code&lt;/a&gt; for managing Keycloak authorization services programmatically. To be perfectly honest, there is no separate Keycloak authorization services REST API. While the authorization services do support the UMA &lt;a href=&#34;https://www.keycloak.org/docs/latest/authorization_services/#_service_protection_api&#34;&gt;Protection API&lt;/a&gt;, that API is only needed if you want your &lt;em&gt;resource servers&lt;/em&gt; (e.g. webapps) to be able manage their own authorization services configuration inside Keycloak. For example, you might want to provide your webapp users the capability to grant access (e.g. read, write) to their own resources to &lt;em&gt;other&lt;/em&gt; users. In this article we &lt;em&gt;will not&lt;/em&gt; cover the Protection API at all.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Debugging Keycloak OIDC token exchange</title>
				<link>https://www.puppeteers.net/blog/debugging-keycloak-oidc-token-exchange/</link>
				<pubDate>Wed, 22 Mar 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/debugging-keycloak-oidc-token-exchange/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-pixabay-532173.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;There&amp;rsquo;s no substitute for understanding what you&amp;rsquo;re doing, and that in turn is difficult without seeing what is happening. Debugging Keycloak OIDC problems without understanding what is happening under the hood is no exception to this rule. The purpose of this article is twofold:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Help you learn how Keycloak OIDC token exchange work&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Provide you with the tools to debug Keycloak OIDC token exchanges in production environments&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;For the purposes of this blog post I&amp;rsquo;ve been using the &lt;a href=&#34;https://github.com/PacktPublishing/Keycloak-Identity-and-Access-Management-for-Modern-Applications&#34;&gt;OpenID Connect Playground&lt;/a&gt; application from the book &lt;a href=&#34;https://www.packtpub.com/product/-keycloak-identity-and-access-management-for-modern-applications/9781800562493&#34;&gt;Keycloak - Identity and Access Management for Modern Applications&lt;/a&gt; from Packt Publishing. I can recommend that book for anyone who needs to understand Keycloak and in particular the protocols it supports (OAuth2, OIDC and SAML 2.0).&lt;/p&gt;</description>
			</item>
			<item>
				<title>Keycloak authorization services: terminology</title>
				<link>https://www.puppeteers.net/blog/keycloak-authorization-services-terminology/</link>
				<pubDate>Fri, 17 Mar 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/keycloak-authorization-services-terminology/</guid>
				<description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/adding-new-permission-to-shared-resources-with-keycloak-rest-api/&#34;&gt;Keycloak Authorization Services&lt;/a&gt; are built on top of well-known standards such as the &lt;a href=&#34;https://oauth.net/2/&#34;&gt;OAuth2&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/User-Managed_Access&#34;&gt;User-Managed Access&lt;/a&gt; specifications (UMA). You can manage Keycloak Authorization Services programmatically, if needed, as described in our other &lt;a href=&#34;https://www.puppeteers.net/blog/adding-new-permission-to-shared-resources-with-keycloak-rest-api/&#34;&gt;blog post&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;OAuth2 clients (such as front end applications) can obtain &lt;em&gt;access tokens&lt;/em&gt; from the server using the &lt;em&gt;token endpoint&lt;/em&gt; and use these tokens to access &lt;em&gt;resources&lt;/em&gt; protected by a &lt;em&gt;resource server&lt;/em&gt; (such as back end services).&lt;/p&gt;&#xA;&lt;p&gt;In the same way, Keycloak Authorization Services provide extensions to OAuth2 to allow access tokens to be issued based on the processing of all &lt;em&gt;policies&lt;/em&gt; associated with the &lt;em&gt;resource(s)&lt;/em&gt; or &lt;em&gt;scope(s)&lt;/em&gt; being requested. This means that resource servers can enforce access to their protected resources based on the &lt;em&gt;permissions&lt;/em&gt; granted by the server and held by an access token. In Keycloak Authorization Services the access token with permissions is called a &lt;em&gt;Requesting Party Token&lt;/em&gt; or &lt;em&gt;RPT&lt;/em&gt; for short.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Let&#39;s Encrypt on AWS: when, where and why</title>
				<link>https://www.puppeteers.net/blog/lets-encrypt-on-aws-when-where-and-why/</link>
				<pubDate>Wed, 15 Mar 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/lets-encrypt-on-aws-when-where-and-why/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Canofworms1.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s Encrypt on AWS can be a can of worms if you don&amp;rsquo;t know what you&amp;rsquo;re doing. &lt;a href=&#34;https://commons.wikimedia.org/wiki/File:Canofworms1.png&#34;&gt;Photo credit&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://letsencrypt.org/how-it-works/&#34;&gt;Let&amp;rsquo;s Encrypt&lt;/a&gt; and the ACME protocol enable getting free (as in beer) TLS/SSL certificates. The main use for Let&amp;rsquo;s Encrypt is to enable HTTPS on web servers. Let&amp;rsquo;s Encrypt TLS certificates expire pretty quickly, in 3 months, but the idea is that renewal is automated so that you don&amp;rsquo;t ever really have to worry about expiration, unlike with commercial TLS certificates, which you typically need to manually renew every 12 months. Using Let&amp;rsquo;s Encrypt on &lt;a href=&#34;https://aws.amazon.com&#34;&gt;AWS&lt;/a&gt; is in &lt;em&gt;some cases&lt;/em&gt; a very viable option, but not so much in others. In many cases trying to use Let&amp;rsquo;s Encrypt certificates leads you down the path of Lovecraftian horrors and madness. Because &amp;ldquo;it all depends&amp;rdquo; I&amp;rsquo;ll try to explain when using Let&amp;rsquo;s Encrypt is viable in the AWS context and when you really should &lt;em&gt;just give up&lt;/em&gt; an use certificates generated by the Amazon Certificate Manager (&amp;ldquo;ACM&amp;rdquo;) instead.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Wrong Route53 domain contact details</title>
				<link>https://www.puppeteers.net/blog/wrong-route53-domain-contact-details/</link>
				<pubDate>Thu, 02 Mar 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/wrong-route53-domain-contact-details/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-pixabay-4169741.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-symptoms&#34;&gt;The symptoms&lt;/h2&gt;&#xA;&lt;p&gt;I recently received and email from Amazon Route53 asking me to verify the contact details for one of our registered DNS domains (replaced here with example.org). And sure enough, I saw wrong Route53 domain contact details in the email:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Subject: Confirm that contact information for example.org is correct.&#xA;Message body:&#xA;&#xA;Dear AWS customer,&#xA;&#xA;This message is a reminder to help you keep the contact information for your domain registration up to date. WHOIS records include the following information:&#xA;&#xA;  Domains:&#xA;  example.org&#xA;&#xA;  Registrant:&#xA;  Name: On behalf of example.org owner&#xA;  Organization Name: Identity Protection Service&#xA;  Address: PO Box 786&#xA;  City: Hayes&#xA;  State/Province: Middlesex&#xA;  Country: GB&#xA;  Postal Code: UB3 9TR&#xA;&#xA;  Administrative Contact:&#xA;  Name: On behalf of example.org owner&#xA;  Organization Name: Identity Protection Service&#xA;  Address: PO Box 786&#xA;  City: Hayes&#xA;  State/Province: Middlesex&#xA;  Country: GB&#xA;  Postal Code: UB3 9TR&#xA;  Phone: +44.1483307527&#xA;  Fax: +44.1483304031&#xA;  Email: e793d865-97ab-42ab-805c-50cc36fd9202@identity-protect.org&#xA;&#xA;  Technical Contact:&#xA;  Name: On behalf of example.org owner&#xA;  Organization Name: Identity Protection Service&#xA;  Address: PO Box 786&#xA;  City: Hayes&#xA;  State/Province: Middlesex&#xA;  Country: GB&#xA;  Postal Code: UB3 9TR&#xA;  Phone: +44.1483307527&#xA;  Fax: +44.1483304031&#xA;  Email: e793d865-97ab-42ab-805c-50cc36fd9202@identity-protect.org&#xA;&#xA;The contact information provided above is what is shown in the public WHOIS. If your domain is privacy protected, the information will be different than the contact data you have submitted. To verify your contact information, please open the Amazon Route 53 console to view your current contact information and make any necessary corrections:&#xA;https://console.aws.amazon.com/route53/home#DomainDetail:example.org&#xA;&#xA;If your information is accurate, you do not need to take any action.&#xA;&#xA;Important&#xA;Under the terms of your registration agreement, providing false contact data can be grounds for the cancellation of your domain name registration.&#xA;&#xA;Regards,&#xA;Amazon Route 53 &lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;These wrong Route53 domain contact details originate from &lt;a href=&#34;https://en.wikipedia.org/wiki/WHOIS&#34;&gt;whois data&lt;/a&gt; for the registered domain. One might reasonably expect the whois data to match the contact details for AWS Route53 domain. However, in this case the Route 53 contact details were correct, but whois data &lt;em&gt;seemed&lt;/em&gt; to be out of sync with those.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Keycloak realm SMTP settings with Ansible</title>
				<link>https://www.puppeteers.net/blog/keycloak-realm-smtp-settings-with-ansible/</link>
				<pubDate>Mon, 27 Feb 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/keycloak-realm-smtp-settings-with-ansible/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-brett-jordan-5426403.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Ansible has reasonably good support for managing various aspects of Keycloak. You can use the &lt;a href=&#34;https://docs.ansible.com/ansible/latest/collections/community/general/keycloak_realm_module.html&#34;&gt;community.general.keycloak_realm&lt;/a&gt; module to handle realm management, including Keycloak realm SMTP server settings. However, in the true Ansible fashion the documentation looks good, but does not help you much. In fact, documentation only mentions that the &lt;em&gt;smtp_server&lt;/em&gt; parameter is a dictionary, but that&amp;rsquo;s it. To be honest, that&amp;rsquo;s about as helpful as the description of the &lt;a href=&#34;https://www.keycloak.org/docs-api/15.0/rest-api/index.html#_realmrepresentation&#34;&gt;RealmRepresentation&lt;/a&gt; for Keycloak. This article aims to fill this documentation void. I also want to share some general advise for similar cases that pop up when you &lt;a href=&#34;https://www.puppeteers.net/blog/managing-keycloak-configuration-programmatically/&#34;&gt;manage Keycloak programmatically&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Integrating Twilio SMS and Prometheus Alertmanager</title>
				<link>https://www.puppeteers.net/blog/integrating-twilio-sms-and-prometheus-alertmanager/</link>
				<pubDate>Thu, 16 Feb 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/integrating-twilio-sms-and-prometheus-alertmanager/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/prometheus-logo.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://prometheus.io/&#34;&gt;Prometheus&lt;/a&gt; is a widely used, cloud-native open source monitoring solution. Its alerting component is called &lt;a href=&#34;https://prometheus.io/docs/alerting/latest/alertmanager/&#34;&gt;Alertmanager&lt;/a&gt;, which can send alerts to email, Slack and elsewhere. Both Prometheus and Alertmanager fit very well into the &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code model&lt;/a&gt; as well. &lt;a href=&#34;https://www.twilio.com/docs/sms&#34;&gt;Twilio SMS&lt;/a&gt; is a SMS sending service with consumption-based pricing model with an extensive API. With some effort you can integrate Twilio SMS and Prometheus together as described in this article.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Testing AlertManager webhooks with curl</title>
				<link>https://www.puppeteers.net/blog/testing-alertmanager-webhooks-with-curl/</link>
				<pubDate>Mon, 06 Feb 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/testing-alertmanager-webhooks-with-curl/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-steve-johnson-1256916-scaled.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://prometheus.io&#34;&gt;Prometheus&lt;/a&gt; is a Cloud-native metrics platforms that is very easy to manage with &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt; tools. Prometheus is often couple with Alertmanager which handles alerting and alert routing. AlertManager has good support for various alert transport (e.g. email or slack) but its alerting capabilities can be extended with custom webhooks. When AlertManager is configured to use a webhook in an alert route, it forwards alerts to an HTTPS/HTTP endpoint instead of handling transporting of the alert itself. AlertManager&amp;rsquo;s official documentation gives a rough idea of what kind of payload to use and how to configure the webhook in alertmanager.yaml. What is not documented is how you can send test alerts to the webhook &lt;em&gt;without&lt;/em&gt; having to trigger real (or fake) alerts in Prometheus. While using fake alerts does work, it is a slow, tedious and invasive process. This article shows one way for testing AlertManager webhooks with curl. In our case the target was to speed up testing of changes to &lt;a href=&#34;https://github.com/Swatto/promtotwilio&#34;&gt;promtotwilio&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Helpotusta työsuhde-etujen lataamiseen: Edenred-latausten automatisointi</title>
				<link>https://www.puppeteers.net/blog/edenred-lataus-automaattisesti/</link>
				<pubDate>Fri, 27 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/edenred-lataus-automaattisesti/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Edenred-koodi.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Kyllästyimme Edenred-korttien latauksen kankeuteen ja automatisoimme latausprosessin. Tässä artikkelissa kerrotaan, miten automaatio toteutettiin &lt;strong&gt;CSV-tiedostoilla ja ohjelmistorobotilla&lt;/strong&gt;. Lisäksi artikkelista löytyy linkit GitHub-sivustollemme, josta voit ladata koodit käyttöösi.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;edenred-korttien-lataustapoja&#34;&gt;Edenred-korttien lataustapoja&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://edenred.fi/fi/&#34;&gt;Edenred&lt;/a&gt; on yksi suurimmista suomalaisista työsuhde-etujen tarjoajista. Edenred tarjoaa fyysisiä ja virtuaalisia kortteja, joihin voidaan ladata työntekijöiden lounas-, virike- ja työmatkaetuja. Edenred-korttien lataamiseen on lukuisia tapoja, mutta kaikki ne vaativat merkittävästi käsityötä työntekijän ja/tai työnantajan puolelta. Vaikka työntekijät voivatkin &lt;a href=&#34;https://edenred.fi/fi/knowledge/edunsaaja/miten-teen-lounasedun-saldolatauspyynnon-ja-toistotoiminnon&#34;&gt;automatisoida omat saldolatauspyyntönsä&lt;/a&gt;, pitää työnantajan silti muistaa hyväksyä ne. Tässä artikkelissa esitellään tapa automatisoida Edenred lataus kokonaan CSV-tiedostolla ja Robot Frameworkia käyttävällä ohjelmistorobotilla. Ainoastaan Edenredin lähettämien saldotilauslaskujen maksu pitää tehdä käsin, joskin tämäkin olisi haluttaessa automatisoitavissa.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Adding new permission with Keycloak authorization services REST API</title>
				<link>https://www.puppeteers.net/blog/adding-new-permission-to-shared-resources-with-keycloak-rest-api/</link>
				<pubDate>Sun, 15 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/adding-new-permission-to-shared-resources-with-keycloak-rest-api/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-ryan-miguel-capili-3605822.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;what-does-it-do-this-keycloak-thing&#34;&gt;What does it do, this Keycloak thing?&lt;/h3&gt;&#xA;&lt;p&gt;Dear seasoned keycloaker, as you probably know, &lt;a href=&#34;https://www.keycloak.org/&#34;&gt;Keycloak&lt;/a&gt; is a stable, scalable, programmable and otherwise killer platform to centralize all your identity, authentication and authorization needs. Keycloak supports &lt;em&gt;fine-grained authorization policies&lt;/em&gt; using Keycloak &lt;a href=&#34;https://www.keycloak.org/docs/latest/authorization_services&#34;&gt;authorization services&lt;/a&gt;. We highly recommend reading our &lt;a href=&#34;https://www.puppeteers.net/blog/keycloak-authorization-services-terminology/&#34;&gt;Keycloak authorization services terminology&lt;/a&gt; article before this article. if you don&amp;rsquo;t understand terms, you will have some hard times ahead. The purpose of &lt;em&gt;this article&lt;/em&gt; is to give you an example of how to work with the Keycloak authorization services REST API.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Debugging Terraform AWS UnauthorizedOperation errors</title>
				<link>https://www.puppeteers.net/blog/debugging-terraform-aws-unauthorizedoperation-errors/</link>
				<pubDate>Wed, 11 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/debugging-terraform-aws-unauthorizedoperation-errors/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-jake-young-732894.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;causes-for-the-terraform-aws-unauthorizedoperation-errors&#34;&gt;Causes for the Terraform AWS UnauthorizedOperation errors&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.net/learn/what-is-terraform-and-how-does-it-work/&#34;&gt;Terraform&lt;/a&gt; is an &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt; tool you can use to configure Cloud resources in AWS. When using &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/aws/latest/docs&#34;&gt;Terraform AWS provider&lt;/a&gt; you frequently run into various UnauthorizedOperation errors when creating, modifying or deleting resources. That happens unless you do what you should &lt;em&gt;not&lt;/em&gt; do and let Terraform use an AWS API key tied to an IAM user with full admin privileges. In almost all cases Terraform UnauthorizedOperation errors are caused by missing IAM permissions. It can sometimes be a bit tedious to get to the root cause, because Terraform may not show it in its normal output.&lt;/p&gt;</description>
			</item>
			<item>
				<title>How to disable S3 bucket ACLs</title>
				<link>https://www.puppeteers.net/blog/how-to-disable-s3-bucket-acls/</link>
				<pubDate>Tue, 10 Jan 2023 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/how-to-disable-s3-bucket-acls/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-david-riano-cortes-975771.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;AWS recommends that you disable S3 bucket ACLs for all new buckets. To understand why some background information is needed.&lt;/p&gt;&#xA;&lt;p&gt;AWS S3 providers two ways to manage access to S3 buckets and objects:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Access policies:&lt;/strong&gt; these are standard IAM policies that you attach to users (&amp;ldquo;user policies&amp;rdquo;) or resources (&amp;ldquo;resource-based policies&amp;rdquo;). IAM policies are the recommended method for managing access to Amazon S3 nowadays.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Access Control Lists (ACLs)&lt;/strong&gt;: ACLs are an older access control method for AWS S3. ACL &lt;a href=&#34;https://docs.aws.amazon.com/AmazonS3/latest/userguide/s3-access-control.html&#34;&gt;map to IAM permissions&lt;/a&gt;. ACLs works on the bucket and object (file) file.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Microsoft Teams: a rant</title>
				<link>https://www.puppeteers.net/blog/microsoft-teams-a-rant/</link>
				<pubDate>Sun, 25 Dec 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/microsoft-teams-a-rant/</guid>
				<description>&lt;p&gt;It&amp;rsquo;s time for a brief rant about Microsoft Teams. Before we start I&amp;rsquo;ll state that Teams is probably an ok platform for collaboration when you work for just one organization. But when you need to work with multiple organizations, each with their own Teams, you immediately run into a world of hurt. There are two reasons:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;There are &lt;em&gt;no&lt;/em&gt; third-party clients or plugins for Teams&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Official Teams web and desktop clients force you to actually &lt;em&gt;switch&lt;/em&gt; workspaces (or organizations) if you want to participate in discussions&lt;/p&gt;</description>
			</item>
			<item>
				<title>Convert a hash into JSON in Puppet</title>
				<link>https://www.puppeteers.net/blog/convert-a-hash-into-json-in-puppet/</link>
				<pubDate>Thu, 22 Dec 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/convert-a-hash-into-json-in-puppet/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-jess-loiterton-9259842.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;This article shows you how to convert a hash into JSON in Puppet using a simple &lt;a href=&#34;https://www.puppet.com/docs/puppet/7/lang_template_erb.html&#34;&gt;ERB template&lt;/a&gt; that gets its data from &lt;a href=&#34;https://www.puppet.com/docs/puppet/7/hiera_intro.html&#34;&gt;Hiera&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Suppose you have this data in Hiera:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;myhash:&#xA;  mykey:&#xA;    foo: one&#xA;    bar: two&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Converting a hash into a JSON file on the target node is surprisingly easy. First look up the data:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$myhash = lookup(&amp;#39;myhash&amp;#39;, Hash)&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Then create a simple ERB template (here: &lt;em&gt;mymodule/templates/myhash.erb&lt;/em&gt;)&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform downloads the deprecated azure provider</title>
				<link>https://www.puppeteers.net/blog/terraform-downloads-the-deprecated-azure-provider/</link>
				<pubDate>Tue, 20 Dec 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-downloads-the-deprecated-azure-provider/</guid>
				<description>&lt;p&gt;You are 100% sure that all your Terraform resources are using &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs&#34;&gt;terraform-provider-azurerm&lt;/a&gt;, yet Terraform attempts to download the deprecated &amp;ldquo;azure&amp;rdquo; provider:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ terraform init&#xA;Initializing modules...&#xA;&#xA;Initializing the backend...&#xA;&#xA;Initializing provider plugins...&#xA;- Finding hashicorp/local versions matching &amp;#34;2.2.3&amp;#34;...&#xA;- Finding latest version of hashicorp/azure...&#xA;- Finding hashicorp/azurerm versions matching &amp;#34;3.17.0&amp;#34;...&#xA;- Installing hashicorp/local v2.2.3...&#xA;- Installed hashicorp/local v2.2.3 (signed by HashiCorp)&#xA;- Installing hashicorp/azurerm v3.17.0...&#xA;- Installed hashicorp/azurerm v3.17.0 (signed by HashiCorp)&#xA;╷&#xA;│ Error: Failed to query available provider packages&#xA;│ &#xA;│ Could not retrieve the list of available versions for provider hashicorp/azure: provider registry registry.terraform.io does not have a provider named&#xA;│ registry.terraform.io/hashicorp/azure&#xA;│ &#xA;│ Did you intend to use terraform-providers/azure? If so, you must specify that source address in each module which requires that provider. To see which&#xA;│ modules are currently depending on hashicorp/azure, run the following command:&#xA;│     terraform providers&#xA;╵&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;You grep the state file and find no references to the &amp;ldquo;azure&amp;rdquo; provider. You assume that the cause is some nested module that depends on it, but no, that&amp;rsquo;s not it. You run &amp;ldquo;terraform providers&amp;rdquo; and see that indeed, the &amp;ldquo;azure&amp;rdquo; provider is required:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Azure Private DNS and VPN Gateway</title>
				<link>https://www.puppeteers.net/blog/azure-private-dns-and-vpn-gateway/</link>
				<pubDate>Tue, 13 Dec 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/azure-private-dns-and-vpn-gateway/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-mo-eid-8347501.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-azure-private-dns&#34;&gt;What is Azure Private DNS?&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://learn.microsoft.com/en-us/azure/dns/private-dns-overview&#34;&gt;Azure Private DNS&lt;/a&gt; is a DNS service for Azure virtual networks. You can register a &lt;a href=&#34;https://learn.microsoft.com/en-us/azure/dns/private-dns-privatednszone&#34;&gt;private DNS zone&lt;/a&gt; to Azure Private DNS and then link that zone with one or more virtual networks. If you enable DNS auto-registration for a virtual network, a new resource (e.g. virtual machines and VPN Gateways) will automatically add its IP address to Azure Private DNS. Resources in the linked virtual networks can use entries in Azure Private DNS to locate each other, instead of relying on IP addresses or the default Azure DNS domain. You can make Azure Private DNS and Azure VPN Gateway work together in several ways, some of which this article will describe.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Writing Ansible modules: when and why?</title>
				<link>https://www.puppeteers.net/blog/writing-ansible-modules-when-and-why/</link>
				<pubDate>Wed, 23 Nov 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/writing-ansible-modules-when-and-why/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-harrison-haines-5247937.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-are-ansible-modules&#34;&gt;What are Ansible modules?&lt;/h2&gt;&#xA;&lt;p&gt;Ansible modules provide the &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt; building blocks for your Ansible roles, plays and playbooks. Modules manage things such as packages, files and services. The scope of a module is typically quite narrow: it does one thing but attempts to do it well. Writing custom Ansible modules is not particularly difficult. The first step is to solve the problem with raw Python, then you can convert that Python code to an Ansible module&lt;/p&gt;</description>
			</item>
			<item>
				<title>Software sovereignty: open source in the EU</title>
				<link>https://www.puppeteers.net/blog/software-sovereignty-open-source-in-the-eu/</link>
				<pubDate>Thu, 17 Nov 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/software-sovereignty-open-source-in-the-eu/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/open-source-maturity-model-mindtrek-2022-small.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-software-sovereignty&#34;&gt;What is software sovereignty&lt;/h2&gt;&#xA;&lt;p&gt;Software sovereignty is a subset of &lt;a href=&#34;https://www.europarl.europa.eu/thinktank/en/document/EPRS_BRI%5C%282020%5C%29651992&#34;&gt;digital sovereignty&lt;/a&gt;. In essence, digital sovereignty means controlling your &lt;em&gt;data&lt;/em&gt;, &lt;em&gt;hardware&lt;/em&gt; and &lt;em&gt;software&lt;/em&gt;. In Europe digital sovereignty &lt;a href=&#34;https://ec.europa.eu/info/strategy/priorities-2019-2024/europe-fit-digital-age_en&#34;&gt;has been driven by&lt;/a&gt; the EU. The reason is the reliance on services from big, global US-led vendors such as Amazon, Microsoft and Google. This poses a risk to the EU, just as does reliance on Chinese manufacturing is similarly a risk.&lt;/p&gt;&#xA;&lt;p&gt;These worries are compounded by the threats to democracy posed by rise of authoritarianism (e.g Russia and China) and other threats to democracy, such as Trump&amp;rsquo;s rise to power and the MAGA movement in the US, and the rise of far-right nationalistic parties in various European countries. Without digital sovereignty in general, or software sovereignty in particular, somebody could &amp;ldquo;pull the plug&amp;rdquo; and you would loose access to your own data, hardware and software. Moreover, if you do not control your data, hardware and software, you&amp;rsquo;re capability to innovate is severely hindered.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Version locking Ansible Collections</title>
				<link>https://www.puppeteers.net/blog/version-locking-ansible-collections/</link>
				<pubDate>Tue, 01 Nov 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/version-locking-ansible-collections/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-pixabay-4145791.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-are-ansible-collections&#34;&gt;What are Ansible Collections?&lt;/h2&gt;&#xA;&lt;p&gt;Ansible is an &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt; tool used for configuration management, network device management, orchestration and other tasks. &lt;a href=&#34;https://docs.ansible.com/ansible/latest/user_guide/collections_using.html&#34;&gt;Ansible Collections&lt;/a&gt; are a way to distribute Ansible content such as roles, playbooks and modules. They &lt;a href=&#34;https://docs.ansible.com/ansible/latest/cli/ansible-galaxy.html&#34;&gt;can be downloaded&lt;/a&gt; from Ansible Galaxy, Git repositories or local directories. Basically collections are a more modern packaging format compared to standalone roles which they &lt;a href=&#34;https://docs.ansible.com/ansible/latest/dev_guide/migrating_roles.html&#34;&gt;are in the process of replacing&lt;/a&gt;. Version-locking Ansible Collections allows you to run the exact same Ansible code every time.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Automation use-cases in the Cloud: Red Hat Open Tour 2022 Tallinn</title>
				<link>https://www.puppeteers.net/blog/automation-use-cases-in-the-cloud-red-hat-open-tour-2022-tallinn/</link>
				<pubDate>Fri, 14 Oct 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/automation-use-cases-in-the-cloud-red-hat-open-tour-2022-tallinn/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Red-Hat-Open-Tour-2022-Tallinn-badge-part.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;automation-use-cases-in-the-cloud&#34;&gt;Automation use-cases in the Cloud&lt;/h2&gt;&#xA;&lt;p&gt;Johan Wennerberg, a Solution Architect for Red Hat Nordics in Stockholm gave presentation in &lt;a href=&#34;https://www.redhat.com/en/events/open-tour-tallinn-2022&#34;&gt;Red Hat Open Tour 2022 Tallinn&lt;/a&gt;. In his presentation titled &amp;ldquo;Gain robust repeatability as selfservice, by automating your automation&amp;rdquo; he listed several automation use-cases in the Cloud. Each of these automation use-cases is made possible by automation stacks. The automation stacks are technology stacks that produce business value through automation. In practice you need to build your automation stacks on top of &lt;a href=&#34;https://www.puppeteers.net/blog/understanding-azure-backup-for-linux-vms/&#34;&gt;infrastructure as code&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ansible variable validation with ansible.utils.assert</title>
				<link>https://www.puppeteers.net/blog/ansible-quality-assurance-part-1-ansible-variable-validation-with-assert/</link>
				<pubDate>Thu, 06 Oct 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/ansible-quality-assurance-part-1-ansible-variable-validation-with-assert/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/square-peg-in-round-hole.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;overview-of-ansible-quality-assurance&#34;&gt;Overview of Ansible quality assurance&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.ansible.com/overview/how-ansible-works&#34;&gt;Ansible&lt;/a&gt; is an IT automation engine which you can use for configuration management, orchestration and device management, among other things. While you can get started fast with Ansible, ensuring high-quality, bug-free code can be challenging. Moreover, there&amp;rsquo;s not that much official, high-quality or coherent documentation available on Ansible quality assurance best practices. While low hanging fruit like Ansible variable validation &lt;em&gt;are&lt;/em&gt; available, they are not emphasized in official documentation.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Cloud automation and infrastructure standardization at Red Hat Open Tour 2022</title>
				<link>https://www.puppeteers.net/blog/cloud-automation-and-infrastructure-standardization-at-red-hat-open-tour-2022/</link>
				<pubDate>Sat, 01 Oct 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/cloud-automation-and-infrastructure-standardization-at-red-hat-open-tour-2022/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Red-Hat-Open-Tour-2022-Tallinn-badge-part.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;We participated in &lt;a href=&#34;https://www.redhat.com/en/events/open-tour-tallinn-2022&#34;&gt;Red Hat Open Tour 2022 Tallinn&lt;/a&gt; a while back. Johan Wennerberg, who is a Solution Architect for Red Hat Nordics in Stockholm, gave a presentation titled &amp;ldquo;Gain robust repeatability as self.service, by automating your automation&amp;rdquo;. Among other things he discussed the importance and use-cases of Cloud infrastructure standardization and automation. Here I willsummarize his views on standardization and automation and explain how they tie in with our focus on &lt;em&gt;quality&lt;/em&gt; in the Cloud infrastructure and elsewhere.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Importing DNS records from Cloudflare to Terraform</title>
				<link>https://www.puppeteers.net/blog/importing-dns-records-from-cloudflare-to-terraform/</link>
				<pubDate>Fri, 30 Sep 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/importing-dns-records-from-cloudflare-to-terraform/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/bpmn-cloudflare-dns2.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Computers were supposed to relieve us humans from boring and repetitive jobs. Here we turn this upside down and do the boring and repetitive job of a computer by importing Cloudflare DNS records to Terraform ourselves. Not fun, but someone’s gotta do it sometimes. If you’re reading this, that someone is probably you. Condolences. My hope is that someone lazy enough gets bored enough to write a program to do this. I didn’t. Yet. &lt;/p&gt;</description>
			</item>
			<item>
				<title>Azure function monitoring with Azure Monitor and Application Insights</title>
				<link>https://www.puppeteers.net/blog/azure-function-monitoring-wiht-azure-monitor-and-application-insights/</link>
				<pubDate>Mon, 26 Sep 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/azure-function-monitoring-wiht-azure-monitor-and-application-insights/</guid>
				<description>&lt;p&gt;Microsoft Azure provides a metrics and monitoring framework called &lt;a href=&#34;https://learn.microsoft.com/en-us/azure/azure-monitor/&#34;&gt;Azure Monitor&lt;/a&gt;. With it you can monitor your Cloud infrastructure and services running there. You can view graphs of the metrics, alert on threshold and all that usual stuff, just like in &lt;a href=&#34;https://aws.amazon.com/cloudwatch&#34;&gt;AWS Cloudwatch&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Some Cloud resources like &lt;a href=&#34;https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview&#34;&gt;Azure Functions&lt;/a&gt; expose &amp;ldquo;a limited number of useful metrics&amp;rdquo; in Azure Monitor. This is a polite way of saying that the metrics are &amp;ldquo;completely useless&amp;rdquo; for most intents and purposes. For example, an Azure Function that gets triggered a few times a week on an irregular schedule by real people you don&amp;rsquo;t really have any useful metrics in Azure Monitor which you could alert on if something is off.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Red Hat Open Tour 2022: Ansible automation project at Elering</title>
				<link>https://www.puppeteers.net/blog/red-hat-open-tour-2022-tallinn-thoughts-about-ansible-automation-at-elering/</link>
				<pubDate>Sat, 17 Sep 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/red-hat-open-tour-2022-tallinn-thoughts-about-ansible-automation-at-elering/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/Red-Hat-Open-Tour-2022-Tallinn-badge-part.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;We participated in Red Hat Open Tour 2022 Tallinn a few weeks ago. Jaan Tanel Veikesaar from &lt;a href=&#34;https://elering.ee/en&#34;&gt;Elering&lt;/a&gt;, a gas/energy company in Estonia, gave a really nice presentation about their &lt;a href=&#34;https://www.ansible.com/overview/how-ansible-works&#34;&gt;Ansible&lt;/a&gt; automation project. Ansible is a very common &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;infrastructure as code&lt;/a&gt; and automation tool. Below I&amp;rsquo;ll go over Jaan&amp;rsquo;s presentation, adding some comments and key takeaways.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-starting-point-for-the-ansible-automation-project&#34;&gt;The starting point for the Ansible automation project&lt;/h2&gt;&#xA;&lt;p&gt;The starting point at Elering was fairly typical: to create a new VM, one had to go to VSphere, launch a VM and continue from there manually. In other words, automation did not really exist. This started to change when business started to demand more from the IT without adding any more human resources. This essentially made automation a necessity instead of being a luxury. So, they did some research and testing, after which Elering ended up with Ansible. They made this choice in part because whenever an Ansible problem was encountered, they could find an answer easily from the Internet.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform, AWS Cloudfront and CNAMEAlreadyExists error</title>
				<link>https://www.puppeteers.net/blog/terraform-aws-cloudfront-and-cnamealreadyexists-error/</link>
				<pubDate>Sat, 17 Sep 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-aws-cloudfront-and-cnamealreadyexists-error/</guid>
				<description>&lt;p&gt;When you create a distribution, AWS creates several DNS A records with the same name (e.g. &lt;em&gt;d25gma2ea3ckma.cloudfront.net&lt;/em&gt;) which point to IPs the distribution is using. Then, typically, you would define CNAME(s) pointing to that cloudfront.net address in your own DNS. Each Cloudfront distribution has a list of aliases, similar to Subject Alternative Names (&amp;ldquo;SAN&amp;rdquo;) in SSL certificates. The aliases should match the CNAME(s) you&amp;rsquo;ve set in DNS.&lt;/p&gt;&#xA;&lt;p&gt;Now, this is all good until you need to migrate those Cloudfront distributions to, say, a new AWS account. If you attempt to create a new distribution (here with Terraform) with the same alias you will get this error:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Enabling Azure Backup on Linux VMs with Terraform</title>
				<link>https://www.puppeteers.net/blog/enabling-azure-backup-on-linux-vms-with-terraform/</link>
				<pubDate>Mon, 05 Sep 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/enabling-azure-backup-on-linux-vms-with-terraform/</guid>
				<description>&lt;p&gt;This article shows you how to enable Azure Backup on Linux VMs. It is recommended to read the &lt;a href=&#34;https://www.puppeteers.net/blog/understanding-azure-backup-for-linux-vms/&#34;&gt;Understanding Azure Backup for Linux VMs&lt;/a&gt; article first before trying to enable backups with Terraform. Terraform AzureRM provider has three relevant resources:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_virtual_machine&#34;&gt;azurerm_linux_virtual_machine&lt;/a&gt;: parameters &lt;em&gt;provision_vm_agent&lt;/em&gt; and &lt;em&gt;allow_extension_operations&lt;/em&gt; should be &lt;em&gt;true&lt;/em&gt; or enabling backups will fail (with or without Terraform)&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_machine_extension&#34;&gt;azurerm_virtual_machine_extension&lt;/a&gt;: this can be used to run/enable a VM extension on a VM&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/backup_protected_vm&#34;&gt;azurerm_backup_protected_vm&lt;/a&gt;: this resource enables backups on a VM&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/recovery_services_vault&#34;&gt;azurerm_recovery_services_vault&lt;/a&gt;: the recovery services vault where backups will be stored&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/backup_policy_vm&#34;&gt;azurerm_backup_policy_vm&lt;/a&gt;: backup schedule and retainment rules&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I&amp;rsquo;ll go through the basic process first, which may work for some people. I&amp;rsquo;ll then take a deep dive into the timeout issues you &lt;em&gt;may&lt;/em&gt; or &lt;em&gt;may not&lt;/em&gt; encounter in your environment.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Understanding Azure Backup for Linux VMs</title>
				<link>https://www.puppeteers.net/blog/understanding-azure-backup-for-linux-vms/</link>
				<pubDate>Mon, 29 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/understanding-azure-backup-for-linux-vms/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://docs.microsoft.com/en-us/azure/backup/backup-overview&#34;&gt;Azure Backup&lt;/a&gt; is an Azure service that allows, among other things, backing up Windows and Linux VMs in Azure. The backups are essentially virtual machine snapshots, but backing up and/or restoring individual files is also possible. This article tries to explain how Azure Backup and Linux VMs interact and what is required for them to work. If you&amp;rsquo;re interested in using Terraform to configure Azure Backup, please have a look at the &lt;a href=&#34;https://www.puppeteers.net/blog/enabling-azure-backup-on-linux-vms-with-terraform/&#34;&gt;Enabling Azure Backup on Linux VMs with Terraform&lt;/a&gt; article.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform: converting an  aws_instance network interface into an explicitly managed interface</title>
				<link>https://www.puppeteers.net/blog/terraform-converting-an-aws_instance-network-interface-into-an-explicitly-managed-interface/</link>
				<pubDate>Tue, 23 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-converting-an-aws_instance-network-interface-into-an-explicitly-managed-interface/</guid>
				<description>&lt;p&gt;The &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance&#34;&gt;aws_instance resource&lt;/a&gt; in Terraform can automatically create the default network interface for you. There are cases, however, when you notice that the default network interface is not enough anymore, and modifying it via the limited aws_instance parameters is not sufficient. In these cases you &lt;em&gt;can&lt;/em&gt; convert the interface into an &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/network_interface&#34;&gt;aws_network_interface resource&lt;/a&gt;, but the process is far from straightforward.&lt;/p&gt;&#xA;&lt;p&gt;The first step is to create a Terraform resource for the network interface:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform, Azure and MissingSubscriptionRegistration</title>
				<link>https://www.puppeteers.net/blog/terraform-azure-and-missingsubscriptionregistration/</link>
				<pubDate>Sat, 20 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-azure-and-missingsubscriptionregistration/</guid>
				<description>&lt;p&gt;When deploying with Terraform to Azure you may sometimes encounter errors such as this:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;╷                                                                                                                                                             &#xA;│ Error: creating Automation Account (Subscription: &amp;#34;83fa140a-2bea-175a-395c-914cae2902ce&amp;#34;                                                                    &#xA;│ Resource Group Name: &amp;#34;production&amp;#34;                                             &#xA;│ Automation Account Name: &amp;#34;backup-automation&amp;#34;): automationaccount.AutomationAccountClient#CreateOrUpdate: Failure responding to request: StatusCode=409 -- Or&#xA;iginal Error: autorest/azure: Service returned an error. Status=409 Code=&amp;#34;MissingSubscriptionRegistration&amp;#34; Message=&amp;#34;The subscription is not registered to use &#xA;namespace &amp;#39;Microsoft.Automation&amp;#39;. See https://aka.ms/rps-not-found for how to register subscriptions.&amp;#34; Details=[{&amp;#34;code&amp;#34;:&amp;#34;MissingSubscriptionRegistration&amp;#34;,&amp;#34;mes&#xA;sage&amp;#34;:&amp;#34;The subscription is not registered to use namespace &amp;#39;Microsoft.Automation&amp;#39;. See https://aka.ms/rps-not-found for how to register subscriptions.&amp;#34;,&amp;#34;targe&#xA;t&amp;#34;:&amp;#34;Microsoft.Automation&amp;#34;}]&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;The problem is that in Azure you may need to register the &lt;em&gt;provider&lt;/em&gt; for the service you intend to manage with Terraform. If you add resources from Azure Portal this registration part is handled automation. In the above case the Azure Automation provider was missing.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Finding which MySQL/MariaDB tables are modified by a GUI</title>
				<link>https://www.puppeteers.net/blog/finding-which-mysql-mariadb-tables-are-modified-by-a-gui/</link>
				<pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/finding-which-mysql-mariadb-tables-are-modified-by-a-gui/</guid>
				<description>&lt;p&gt;I was working with &lt;a href=&#34;https://www.keycloak.org/&#34;&gt;Keycloak&lt;/a&gt; realm private/public key automation and it was not immediately obvious where Keycloak stores the keys. Figuring it out was actually easy, and this method applies to any web application that uses MySQL/MariaDB, not just Keycloak.&lt;/p&gt;&#xA;&lt;p&gt;Anyhow, on Ubuntu, you&amp;rsquo;d navigate to &lt;em&gt;/var/lib/mysql/name-of-database&lt;/em&gt;. For example:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;cd /var/lib/mysql/keycloak&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Make sure that no changes have been made recently (within one minute):&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ find -mmin -1&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Then go to the web application and change whatever you&amp;rsquo;re trying to locate from the database. Here I changed the Keycloak RSA key priority. Then run the find command again:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Managing custom realm keys in Keycloak programmatically</title>
				<link>https://www.puppeteers.net/blog/managing-custom-realm-keys-in-keycloak-programmatically/</link>
				<pubDate>Fri, 19 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/managing-custom-realm-keys-in-keycloak-programmatically/</guid>
				<description>&lt;h2 id=&#34;what-are-keycloak-realm-keys&#34;&gt;What are Keycloak realm keys?&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.keycloak.org/&#34;&gt;Keycloak&lt;/a&gt;&amp;rsquo;s authentication protocols make use of private and public keys for signing and encrypting, as described in the &lt;a href=&#34;https://www.keycloak.org/docs/latest/server_admin/index.html#realm_keys&#34;&gt;official documentation&lt;/a&gt;. These keys are realm-specific, and by default managed internally in Keycloak. So, when you create a realm using the Keycloak Admin API, kcadm.sh or manually using the Web UI, new keypair(s) get generated automatically. These are called &amp;ldquo;Managed keys&amp;rdquo;. However, you can also use custom realm keys in Keycloak, which is what this article is about. Using custom realm keys allow you, for example, to use a single keypair in multiple realms. When you import a custom private key, Keycloak uses it to automatically create a certificate. If you want, you can pass both a private key and a certificate signed with that private key instead. That way you can bypass Keycloak&amp;rsquo;s automatic certificate generation, should you need to.&lt;/p&gt;</description>
			</item>
			<item>
				<title>AWS: creating AMIs from EBS snapshots shared with you</title>
				<link>https://www.puppeteers.net/blog/aws-creating-amis-from-ebs-snapshots-shared-with-you/</link>
				<pubDate>Mon, 15 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/aws-creating-amis-from-ebs-snapshots-shared-with-you/</guid>
				<description>&lt;p&gt;In AWS &lt;a href=&#34;https://aws.amazon.com/ebs/&#34;&gt;EBS&lt;/a&gt; (&amp;ldquo;Elastic Block Storage&amp;rdquo;) is the underlying technology that (virtual) hard disks of your instances (virtual machines) use. You can take snapshots of those virtual hard disks and use those snapshots to, for example:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Debugging issues with unbootable virtual machines: attach and then mount the snapshot on another virtual machine and investigate what is wrong.&lt;/li&gt;&#xA;&lt;li&gt;Creating AMI images from which you can launch new instances&lt;/li&gt;&#xA;&lt;li&gt;Sharing EBS volumes (between regions and AWS accounts), e.g. for purposes of migrating VMs&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Here we&amp;rsquo;ll focus on the last use-case: being able to create copies of virtual machines on another AWS account. The reason why I even bothered writing this blog post is that most of the articles on the Internet do not cover this use-case: they assume you&amp;rsquo;re working within one AWS account and/or one region. The use-case covered here requires a few extra steps:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Modern cronjob part 1: Azure Automation with Terraform</title>
				<link>https://www.puppeteers.net/blog/modern-cronjob-part-1-azure-automation-with-terraform/</link>
				<pubDate>Thu, 11 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/modern-cronjob-part-1-azure-automation-with-terraform/</guid>
				<description>&lt;p&gt;Microsoft Azure has a nice service for scheduling tasks called &lt;a href=&#34;https://duckduckgo.com/?q=azure&amp;#43;automation&amp;amp;t=newext&amp;amp;atb=v310-1&amp;amp;ia=web&#34;&gt;Azure Automation&lt;/a&gt;. While Azure Automation is able to other things as well, such as being able to act as a Powershell DSC pull server, we&amp;rsquo;ll focus on the runbooks and scheduling. Runbooks are scripts that do things, e.g. run maintenance and reporting tasks. Runbooks often, but not necessarily manipulate objects in Azure. Runbooks are serverless like Azure Functions and the pricing is therefore similar - you pay for the amount of computing resources you use and don&amp;rsquo;t have to pay for a server that&amp;rsquo;s mostly idle.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Joining nodes to FreeIPA using a non-admin user</title>
				<link>https://www.puppeteers.net/blog/joining-nodes-to-freeipa-using-a-non-admin-user/</link>
				<pubDate>Tue, 09 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/joining-nodes-to-freeipa-using-a-non-admin-user/</guid>
				<description>&lt;p&gt;Typically Linux nodes are joined to &lt;a href=&#34;https://www.freeipa.org/page/Main_Page&#34;&gt;FreeIPA&lt;/a&gt; using admin credentials. While this works, it exposes fully privileged credentials unnecessarily, for example when used within a configuration management system (see for example &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-ipa/&#34;&gt;puppet-ipa&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Fortunately joining nodes to FreeIPA is possible with more limited privileges. The first step is to create a new FreeIPA role, e.g. &amp;ldquo;Enrollment administrator&amp;rdquo; with three privileges:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;DNS Administrators&lt;/li&gt;&#xA;&lt;li&gt;Host Administrators&lt;/li&gt;&#xA;&lt;li&gt;Host Enrollment&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Then you create a new user, e.g. &amp;ldquo;enrollment&amp;rdquo;, and join it to the &amp;ldquo;Enrollment administrator&amp;rdquo; role. After that you should be able to join nodes using that &amp;ldquo;enrollment&amp;rdquo; user.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using .sync.yml in Puppet Development Kit (PDK)</title>
				<link>https://www.puppeteers.net/blog/using-sync-yml-in-puppet-development-kit-pdk/</link>
				<pubDate>Tue, 09 Aug 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-sync-yml-in-puppet-development-kit-pdk/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://puppet.com/try-puppet/puppet-development-kit/&#34;&gt;Puppet Development Kit&lt;/a&gt; is probably the best thing since sliced bread if you work a lot with Puppet. It makes adding basic validation and unit tests trivial with help from &lt;a href=&#34;https://rspec-puppet.com/&#34;&gt;rspec-puppet&lt;/a&gt;. It also makes it very easy to build module packages for the &lt;a href=&#34;https://forge.puppet.com/&#34;&gt;Puppet Forge&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;That said, there is a minor annoyance with it: whenever you run &amp;ldquo;pdk update&amp;rdquo; to update PDK to the latest version, all your local changes to files such as .gitignore get destroyed, because PDK creates those files from &lt;a href=&#34;https://github.com/puppetlabs/pdk-templates/&#34;&gt;PDK templates&lt;/a&gt; and any local changes are mercilessly wiped. Fortunately there is a way to &lt;em&gt;sync&lt;/em&gt; your local changes to the files generated from the templates with &lt;em&gt;.sync.yml&lt;/em&gt;. While .sync.yml is is &lt;a href=&#34;https://github.com/puppetlabs/pdk-templates/blob/main/README.md&#34;&gt;pretty well documented&lt;/a&gt;, documentation is lots and lots of words with very few examples. So, here&amp;rsquo;s a fairly trivial .sync.yml example that ensures local changes to &lt;em&gt;.pdkignore&lt;/em&gt; and &lt;em&gt;.gitignore&lt;/em&gt; persist across PDK updates:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Use content of a file as a variable with Puppet</title>
				<link>https://www.puppeteers.net/blog/load-content-of-a-file-on-an-agent-node-to-a-variable-with-puppet/</link>
				<pubDate>Sat, 16 Jul 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/load-content-of-a-file-on-an-agent-node-to-a-variable-with-puppet/</guid>
				<description>&lt;p&gt;Every now and then a need to use the content of a file as a variable &lt;strong&gt;on an agent node&lt;/strong&gt; arises. Here&amp;rsquo;s one way to do it with the help of a &lt;a href=&#34;https://puppet.com/docs/puppet/7/custom_facts.html&#34;&gt;custom fact&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;First create a custom fact &lt;strong&gt;on the puppet serve&lt;/strong&gt;r:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Facter.add(:my_file_content) do&#xA;  setcode do&#xA;    path = &amp;#34;/path/to/my_file&amp;#34;&#xA;    File.read(path) if File.exist?(path)&#xA;   end&#xA;end&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;You can &lt;strong&gt;confine&lt;/strong&gt; this to restrict it to be available only on selected nodes, for example:&lt;/p&gt;</description>
			</item>
			<item>
				<title>How to add OpenID to WordPress with Keycloak</title>
				<link>https://www.puppeteers.net/blog/how-to-add-openid-to-wordpress-with-keycloak/</link>
				<pubDate>Thu, 14 Jul 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/how-to-add-openid-to-wordpress-with-keycloak/</guid>
				<description>&lt;p&gt;Adding &lt;a href=&#34;https://openid.net/what-is-openid/&#34;&gt;OpenID&lt;/a&gt; to Wordpress allows for existing users on a domain to connect without having to manage another account. In this setup, we will be using Keycloak to provide the existing accounts which the OpenID plugin will use.&lt;/p&gt;&#xA;&lt;p&gt;There are a few plugins for Wordpress that allow this functionality, but we will be using &lt;a href=&#34;https://wordpress.org/plugins/daggerhart-openid-connect-generic/&#34;&gt;OpenID-Connect-Generic&lt;/a&gt; by &lt;a href=&#34;https://www.daggerhartlab.com/&#34;&gt;Daggerhart&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;keycloak-client-setup&#34;&gt;Keycloak Client Setup&lt;/h2&gt;&#xA;&lt;p&gt;First step is to create a client in Keycloak. In the Keycloak web UI, create an &lt;strong&gt;openid-connect&lt;/strong&gt; client by going to &lt;strong&gt;Clients&lt;/strong&gt; and click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Multi-part cloud-init provisioning with Terraform</title>
				<link>https://www.puppeteers.net/blog/multi-part-cloud-init-provisioning-with-terraform/</link>
				<pubDate>Thu, 28 Apr 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/multi-part-cloud-init-provisioning-with-terraform/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://cloud-init.io/&#34;&gt;Cloud-Init&lt;/a&gt; is &amp;ldquo;a standard for customizing&amp;rdquo; cloud instances, typically on their first boot. It is allows mixing state-based configuration management with imperative provisioning commands (details in &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;our IaC article&lt;/a&gt;). By using cloud-init most of the annoyances of SSH-based provisioning can be avoided:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Having to use (possibly shared) SSH keys for provisioning&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Having to have direct network access to the VM being provisioned (may require a VPN connection)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;That said, neither cloud-init itself, nor its use within Terraform is particularly well documented. Therefore it can be an effort to create cloud-init-based provisioning that works &lt;em&gt;and&lt;/em&gt; adapts easily to different use-cases. This article attempts to fill that gap to some extent.&lt;/p&gt;</description>
			</item>
			<item>
				<title>X11 Connection Rejected</title>
				<link>https://www.puppeteers.net/blog/x11-connection-rejected/</link>
				<pubDate>Thu, 28 Apr 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/x11-connection-rejected/</guid>
				<description>&lt;p&gt;When switching to root after the typical SSH with X11 forwarding enabled this error can appear:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ X11 connection rejected because of wrong authentication.&#xA;$ Error: Can&amp;#39;t open display: localhost:10.0&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;The workaround seems to include copying the &lt;strong&gt;MIT-MAGIC-COOKIE-1&lt;/strong&gt; from the user who ssh&amp;rsquo;d in to the root user using xauth. Here&amp;rsquo;s how:&lt;/p&gt;&#xA;&lt;p&gt;First verify the &lt;strong&gt;$DISPLAY&lt;/strong&gt; being used and list the &lt;strong&gt;MIT-MAGIC-COOKIE-1&lt;/strong&gt; used for it :&lt;/p&gt;</description>
			</item>
			<item>
				<title>Data-driven Terraform: Kubernetes cluster in Hetzner Cloud</title>
				<link>https://www.puppeteers.net/blog/data-driven-terraform-kubernetes-cluster-in-hetzner-cloud/</link>
				<pubDate>Fri, 15 Apr 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/data-driven-terraform-kubernetes-cluster-in-hetzner-cloud/</guid>
				<description>&lt;p&gt;Terraform does not have a particularly strong decoupling between &lt;em&gt;data&lt;/em&gt; and &lt;em&gt;code&lt;/em&gt;, at least not from a best practices perspective. It is possible and useful, however, to use data to define Terraform resources - if not for any other reason but to reduce code repetition for common resources that require defining lots of parameters. Here&amp;rsquo;s an example of setting up a Kubernetes cluster in Hetzner Cloud using Terraform with a &amp;ldquo;data-driven&amp;rdquo; approach:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Enabling system tray on Fedora 35 and 36</title>
				<link>https://www.puppeteers.net/blog/enabling-system-tray-on-fedora-35/</link>
				<pubDate>Tue, 12 Apr 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/enabling-system-tray-on-fedora-35/</guid>
				<description>&lt;p&gt;System tray is a &amp;ldquo;legacy&amp;rdquo; tray where various applications (e.g. Nextcloud, Pidgin and Signal) have an icon with which you can interact with the application without actually opening the main application window. I said &amp;ldquo;legacy&amp;rdquo;, because phasing it out was the plan in the Gnome 3 project, but it seems like we&amp;rsquo;re not getting rid of the tray any time soon, if ever.&lt;/p&gt;&#xA;&lt;p&gt;In any case the system tray is not enabled by default in recent Fedoras, and the proper way to enable it has changed several times in the recent past as Gnome has been upgraded. This outlines the most recent way to do it, and hopefully this one sticks for longer than a year or so.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform Enum data type</title>
				<link>https://www.puppeteers.net/blog/terraform-enum-data-type/</link>
				<pubDate>Tue, 12 Apr 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-enum-data-type/</guid>
				<description>&lt;p&gt;In Terraform you have access to basic data types like &lt;em&gt;bool&lt;/em&gt; or &lt;em&gt;string&lt;/em&gt;. Defining the data type is a good start for starting to improve the quality of your modules. However, you may want to validate that a certain string matches a list of pre-defined options, and if not, fail validation early.&lt;/p&gt;&#xA;&lt;p&gt;Terraform, &lt;a href=&#34;https://puppet.com/docs/puppet/7/lang_data_abstract.html#enum-data-type&#34;&gt;unlike Puppet&lt;/a&gt;, does not have a built-in Enum data type. However, you can emulate an Enum like this:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Debugging Puppet Bolt inventory plugins</title>
				<link>https://www.puppeteers.net/blog/debugging-puppet-bolt-inventory-plugins/</link>
				<pubDate>Mon, 14 Mar 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/debugging-puppet-bolt-inventory-plugins/</guid>
				<description>&lt;p&gt;Puppet Bolt handles &lt;a href=&#34;https://puppet.com/docs/bolt/latest/inventory_files.html&#34;&gt;inventories&lt;/a&gt; in a very flexible and powerful manner: you can combine static target definitions and different targets into a single inventory. For example, you can have an inventory which defines some static node names combined with the &lt;a href=&#34;https://forge.puppet.com/modules/puppetlabs/aws_inventory&#34;&gt;AWS inventory&lt;/a&gt;, or one that combines static nodes with the &lt;a href=&#34;https://forge.puppet.com/modules/dylanratcliffe/bolt_vagrant/readme&#34;&gt;Vagrant inventory&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Puppet Bolt inventory plugins do their magic and then output what is essentially a static inventory generated dynamically. When dynamic inventory plugins do not work (as &lt;a href=&#34;https://github.com/dylanratcliffe/bolt_vagrant/pull/5&#34;&gt;in my case&lt;/a&gt;) it can be challenging to figure out what is wrong, let alone how to fix it. However, there&amp;rsquo;s is a very handy way to print out a static version of the entire inventory, including the dynamically created content:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform remote-exec: wait until a webpage is reachable</title>
				<link>https://www.puppeteers.net/blog/terraform-remote-exec-wait-until-a-webpage-is-reachable/</link>
				<pubDate>Fri, 18 Feb 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-remote-exec-wait-until-a-webpage-is-reachable/</guid>
				<description>&lt;p&gt;Terraform&amp;rsquo;s remote-exec provisioner fails immediately if any command in a script exists with a non-zero exit code. This makes building polling loops a bit more involved than it normally is. So, here is an example loop that checks if a URL can be reached:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;while true; do&#xA;    curl -k https://puppet:8140/puppet-ca/v1 &amp;amp;&amp;amp; break || sleep 3&#xA;done&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;When the URL is unreachable, the &amp;ldquo;||&amp;rdquo; will ensure that &amp;ldquo;sleep&amp;rdquo; gets run, which returns 0. If the URL is reachable, curl itself will return 0 and &amp;ldquo;&amp;amp;&amp;amp;&amp;rdquo; ensures that we break out of the loop.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Are Corporate Vision awards fake?</title>
				<link>https://www.puppeteers.net/blog/is-small-business-awards-a-scam/</link>
				<pubDate>Thu, 10 Feb 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/is-small-business-awards-a-scam/</guid>
				<description>&lt;p&gt;This was a burning question in my head in September 2021 but didn&amp;rsquo;t have much luck googling it. Here&amp;rsquo;s our experience and analysis of Small Business Awards by Corporate Vision. Read on to find out whether the awards handed out by Corporate Vision awards truly are a legit or not.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-did-we-hear-about-corporate-vision&#34;&gt;How did we hear about Corporate Vision?&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.corporatevision-news.com&#34;&gt;Corporate Vision&lt;/a&gt; contacted us in September 2021 announcing us that we were nominated as candidate for being the best company in the &amp;lsquo;IT Infrastructure Management Specialists - Finland&amp;rsquo; category for &lt;a href=&#34;https://www.corporatevision-news.com/awards/small-business-awards/&#34;&gt;Small Business Awards&lt;/a&gt;. At that time (before this blog post) there was very little information online about Small Business Awards or the company behind them. What I learned at that time was that they seemed to be a so-called &amp;lsquo;vanity award&amp;rsquo;, where winners have been preselected and everything else was just for show. We could not be absolutely sure about that then, and we thought that &amp;ldquo;winning&amp;rdquo; might have some marketing value, so we decided to play along and see where it leads us. I will first go through the process, then I&amp;rsquo;ll try to give an answer the question in the title.&lt;/p&gt;</description>
			</item>
			<item>
				<title>How software companies can end up in a Cloud hell, and how to fix it</title>
				<link>https://www.puppeteers.net/blog/how-software-companies-can-end-up-in-a-cloud-hell-and-how-to-fix-it/</link>
				<pubDate>Thu, 10 Feb 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/how-software-companies-can-end-up-in-a-cloud-hell-and-how-to-fix-it/</guid>
				<description>&lt;h2 id=&#34;the-slippery-slope&#34;&gt;The slippery slope&lt;/h2&gt;&#xA;&lt;p&gt;Custom software development services are in high demand today. Organizations are willing to pay considerable amounts of money for development of custom software, be it mobile applications relying on backend services in the Cloud, or tailoring of open source software to better fit their needs. This has provided the impetus for rapid growth of companies that provide software development services. Some of these companies simply rent developers to clients, others work on customer projects handling both project management and development.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hiera lookups in rspec-puppet</title>
				<link>https://www.puppeteers.net/blog/hiera-lookups-in-rspec-puppet/</link>
				<pubDate>Wed, 09 Feb 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/hiera-lookups-in-rspec-puppet/</guid>
				<description>&lt;p&gt;While &lt;a href=&#34;https://rspec-puppet.com/&#34;&gt;rspec-puppet documentation&lt;/a&gt; is quite decent, it does not really explain how to test classes that get their parameters via Hiera lookups, such as profiles in the &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-workflow-part-4-roles-and-profiles/&#34;&gt;roles and profiles pattern&lt;/a&gt;. Several parameters related to Hiera are listed in the &lt;a href=&#34;https://rspec-puppet.com/documentation/configuration/&#34;&gt;rspec-puppet configuration reference&lt;/a&gt;, but that&amp;rsquo;s all. The other documentation you find on the Internet is generally outdated and not applicable for modules converted with &lt;a href=&#34;https://puppet.com/try-puppet/puppet-development-kit/&#34;&gt;PDK&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In this article we show how to test an &amp;ldquo;ipa_client&amp;rdquo; class that uses lookups to get its parameter from Hiera. It used to be a profile that was later separated from the &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-puppet-workflow-part-1-the-control-repository/&#34;&gt;control-repo&lt;/a&gt; into a separate module, which means that rspec-puppet does not have access to the control-repo&amp;rsquo;s Hiera data.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Mautic spam prevention</title>
				<link>https://www.puppeteers.net/blog/mautic-spam-prevention/</link>
				<pubDate>Mon, 07 Feb 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/mautic-spam-prevention/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.mautic.org/&#34;&gt;Mautic&lt;/a&gt; is a widely used open source email marketing automation application written in PHP. Email marketing is typically used in conjunction with &lt;a href=&#34;https://www.hubspot.com/inbound-marketing&#34;&gt;inbound marketing&lt;/a&gt; done by asking people to give their email address in exchange for something, like a free ebook or a newsletter with good content. As you&amp;rsquo;re asking for the email address on a publicly facing webpage, spambots will find your form, and start misusing it to send your &amp;ldquo;Welcome&amp;rdquo; emails all over the place. This in turn may result in lots of bounces and/or complaints, which may get you locked out from your email service provider unless you pay attention. So, you need a way to block or fool those spam bots to prevent such issues, and to keep the Mautic database clean.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Windows domain in Azure</title>
				<link>https://www.puppeteers.net/blog/windows-domain-in-azure/</link>
				<pubDate>Tue, 11 Jan 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/windows-domain-in-azure/</guid>
				<description>&lt;p&gt;I wrote this article to better understand all the pieces called &amp;ldquo;AD&amp;rdquo; or &amp;ldquo;Active Directory&amp;rdquo; in Microsoft Azure fit together. The pieces are as follows:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;Active Directory (AD)&lt;/strong&gt;: The is the classic on-premise Active Directory with LDAP, Kerberos, group policies and all that. Traditionally Windows machines in larger environments have been domain-joined to on-premise AD.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://docs.microsoft.com/en-us/windows-server/identity/active-directory-federation-services&#34;&gt;Active Directory Federation services (AD FS)&lt;/a&gt;&lt;/strong&gt;: adds support for modern web-SSO protocols (SAML, OAuth 2.0 and OIDC) to on-premise Active Directory.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Conditional provisioner blocks in Terraform</title>
				<link>https://www.puppeteers.net/blog/conditional-provisioner-blocks-in-terraform/</link>
				<pubDate>Wed, 05 Jan 2022 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/conditional-provisioner-blocks-in-terraform/</guid>
				<description>&lt;p&gt;I&amp;rsquo;ll start with a spoiler: what the title suggests is not possible. It is, however, possible to accomplish this with cloud-init and Terraform templates as described in the &lt;a href=&#34;https://www.puppeteers.net/blog/multi-part-cloud-init-provisioning-with-terraform/&#34;&gt;Multi-part cloud-init provisioning with Terraform&lt;/a&gt; blog post.&lt;/p&gt;&#xA;&lt;p&gt;If you need to use SSH/WinRM provisioning, then there are various workarounds you can apply, and this article explains some of them and goes into depth into one in particular.&lt;/p&gt;&#xA;&lt;p&gt;The first workaround is relatively clean, but is not usable in all cases, especially when working with complex modules. The idea is to have two resources, here of type &lt;em&gt;aws_instance&lt;/em&gt;. Those resources are identical except for the provisioner blocks:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Showing SQL statements with Keycloak</title>
				<link>https://www.puppeteers.net/blog/showing-sql-statements-with-keycloak/</link>
				<pubDate>Fri, 31 Dec 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/showing-sql-statements-with-keycloak/</guid>
				<description>&lt;p&gt;Sometimes you might find yourself wondering whether there is some paranormal activity going on with your keycloak and its database. To check if things are still in the realm of physical reality, and to restore your child&amp;rsquo;s faith in the programmer who never makes mistakes, it might be soothing to check what&amp;rsquo;s actually happening to the database. To do this, create a new property named &lt;strong&gt;showSql&lt;/strong&gt; and give it a value of &lt;strong&gt;true&lt;/strong&gt; in your connectionsJpa spi. This is located in standalone.xml, standalone-ha.xml, or in domain.xml (if you&amp;rsquo;ve already graduated from kindergarten).&lt;/p&gt;</description>
			</item>
			<item>
				<title>Serverless Puppet with control repo, Hiera, roles and profiles and Puppet Bolt</title>
				<link>https://www.puppeteers.net/blog/serverless-puppet-with-control-repo-hiera-roles-and-profiles-and-puppet-bolt/</link>
				<pubDate>Tue, 28 Dec 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/serverless-puppet-with-control-repo-hiera-roles-and-profiles-and-puppet-bolt/</guid>
				<description>&lt;p&gt;The traditional way of managing systems with &lt;a href=&#34;https://www.puppeteers.net/learn/what-is-puppet-and-how-does-it-work/&#34;&gt;Puppet&lt;/a&gt; is to install Puppet agent on the nodes being managed and point those agents to a Puppet server (more details &lt;a href=&#34;https://www.puppeteers.net/learn/what-is-puppet-and-how-does-it-work/&#34;&gt;here&lt;/a&gt;). This approach works well for environments with tens or hundreds of nodes, but is an overkill for small environments with just a handful of nodes. Fortunately nowadays &lt;a href=&#34;https://puppet.com/docs/bolt/latest/bolt.html&#34;&gt;Puppet Bolt&lt;/a&gt; enables you to &lt;a href=&#34;https://www.puppeteers.net/learn/understanding-infrastructure-as-code-iac/&#34;&gt;push&lt;/a&gt; configurations to the managed nodes via SSH and WinRM. When using Bolt the &lt;a href=&#34;https://www.puppeteers.net/learn/what-is-puppet-and-how-does-it-work/&#34;&gt;catalog&lt;/a&gt; (desired state) is created on the computer running Puppet Bolt using facts from managed nodes and then sent to the managed nodes to be applied.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Multiple Bitbucket Cloud accounts with SSH authentication</title>
				<link>https://www.puppeteers.net/blog/multiple-bitbucket-cloud-accounts-with-ssh-authentication/</link>
				<pubDate>Tue, 07 Dec 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/multiple-bitbucket-cloud-accounts-with-ssh-authentication/</guid>
				<description>&lt;p&gt;In Bitbucket usernames are unique across whole of Bitbucket. Moreover, the same SSH key can only be configured for one user. If you registered your Bitbucket account using a corporate email and used your primary SSH key with it, you&amp;rsquo;re pretty much hosed if you then need to create another corporate Bitbucket account and wanted to use the same SSH key with it - that&amp;rsquo;s just not going to happen. The solution to this dilemma is to create another SSH keypair and somehow make SSH, Git and Bitbucket co-operate. As the correct solution was not immediately obvious it is documented here.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Managing OpenVPN-based Azure VPN Gateway certificates with easyrsa3</title>
				<link>https://www.puppeteers.net/blog/managing-openvpn-based-azure-vpn-gateway-certificates-with-easyrsa3/</link>
				<pubDate>Fri, 19 Nov 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/managing-openvpn-based-azure-vpn-gateway-certificates-with-easyrsa3/</guid>
				<description>&lt;p&gt;The Azure VPN Gateway supports the OpenVPN protocol (except the &amp;ldquo;Basic SKU&amp;rdquo;). Unlike, for example, the commercial Access Server, the VPN Gateway does not have a built-in certificate authority (CA) tool for managing client certificates. And client certificates are essentially a requirement if you need to support clients other than Windows and Mac, such as Linux, iOS or Android. The use of easy-rsa-old as a CA for Azure VPN Gateway is documented quite well in this &lt;a href=&#34;https://www.thomasmaurer.ch/2020/02/create-azure-p2s-vpn-with-azure-ad-authentication/&#34;&gt;blog post&lt;/a&gt;, but this post is about using the newer &lt;a href=&#34;https://github.com/OpenVPN/easy-rsa&#34;&gt;easyrsa3&lt;/a&gt; instead. Basic familiarity with easyrsa3 is assumed, so we just go through the steps you&amp;rsquo;d normally take.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Dealing with multiple AWS accounts with one Keycloak client for Single-Sign On</title>
				<link>https://www.puppeteers.net/blog/dealing-with-multiple-aws-accounts-with-one-keycloak-client-for-single-sign-on/</link>
				<pubDate>Thu, 18 Nov 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/dealing-with-multiple-aws-accounts-with-one-keycloak-client-for-single-sign-on/</guid>
				<description>&lt;p&gt;This article assumes that the user backend for Keycloak is &lt;a href=&#34;https://www.freeipa.org/page/Main_Page&#34;&gt;FreeIPA&lt;/a&gt;. Regardless of that the instructions will apply to any other setup with minor modifications. Here we use two different AWS accounts renamed to 123412341234 and 567856785678 to protect the personal information of the innocent. The Keycloak staging cluster on which this integration was done is called &lt;em&gt;id-staging.example.org&lt;/em&gt; and the production cluster is called &lt;em&gt;id.example.org&lt;/em&gt;. The Keycloak realm is EXAMPLE.ORG. Replace those with the values correct for your environment.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Allowing external email forwarding in Office 365</title>
				<link>https://www.puppeteers.net/blog/allowing-external-email-forwarding-in-office-365/</link>
				<pubDate>Tue, 16 Nov 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/allowing-external-email-forwarding-in-office-365/</guid>
				<description>&lt;p&gt;We use Zimbra as our main email server. We also have Office 365 subscription to make working with our clients a bit easier. The challenge is that when customers send us, say, Teams meeting invites, they typically use autofill and the email gets sent to our Office 365 mailboxes which nobody really looks at.&lt;/p&gt;&#xA;&lt;p&gt;It is possible to fix this by configuring email forwarding. That is theoretically possible out of the box on a per-user basis in &lt;a href=&#34;https://outlook.office.com/mail/options/mail/forwarding&#34;&gt;https://outlook.office.com/mail/options/mail/forwarding&lt;/a&gt;. However, when you actually try it out you will get an error message in your Office 365 inbox because forwarding is disabled on the organizational level by default:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Short introduction to Packer and Vagrant</title>
				<link>https://www.puppeteers.net/blog/short-introduction-to-packer-and-vagrant/</link>
				<pubDate>Sun, 31 Oct 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/short-introduction-to-packer-and-vagrant/</guid>
				<description>&lt;p&gt;This article is a short introduction to Packer and Vagrant - tools that we often recommend to our customers but which may be a bit hard to understand if you have no previous expose to them.&lt;/p&gt;&#xA;&lt;h2 id=&#34;packer&#34;&gt;Packer&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.packer.io/&#34;&gt;Packer&lt;/a&gt; is used to “create identical machine images for multiple platforms from a single source configuration”. Packer works in a very simple fashion:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;It reads its configuration file&lt;/li&gt;&#xA;&lt;li&gt;It launches a virtual machine based on the “base box” you’ve defined. The base box would be a “vanilla” Linux distribution such as Ubuntu 20.04.&lt;/li&gt;&#xA;&lt;li&gt;It runs the provisioning scripts you’ve written on the base box (via SSH)&lt;/li&gt;&#xA;&lt;li&gt;It removes deployment-specific things (e.g. SSH host keys)&lt;/li&gt;&#xA;&lt;li&gt;It shuts down the VM&lt;/li&gt;&#xA;&lt;li&gt;It creates a VM image out of base box + your changes&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;After this you can distribute the base box to people and they will have an identical system at their disposal. If you need to modify the image you can just change the provisioning scripts and/or the base image and rebuild. The configuration file can and should be stored in version control repository.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Enabling AWS EC2 instance automatic recovery with Terraform</title>
				<link>https://www.puppeteers.net/blog/enabling-aws-ec2-instance-automatic-recovery-with-terraform/</link>
				<pubDate>Thu, 28 Oct 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/enabling-aws-ec2-instance-automatic-recovery-with-terraform/</guid>
				<description>&lt;p&gt;AWS EC2 instances are subject to two types of status checks (&lt;a href=&#34;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/monitoring-system-instance-status-check.html&#34;&gt;AWS docs&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;System status check (issues with the underlying hardware/networking: &amp;ldquo;the AWS side&amp;rdquo;)&lt;/li&gt;&#xA;&lt;li&gt;Instance status check (issues with the OS, e.g. OOM, file system corruption, broken networking, etc: &amp;ldquo;our side&amp;rdquo;)&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://aws.amazon.com/premiumsupport/knowledge-center/automatic-recovery-ec2-cloudwatch/&#34;&gt;official AWS EC2 instance recovery documentation&lt;/a&gt; claims that automatically recovering from an EC2 instance failure is only possible for system status checks, but the AWS documentation &lt;a href=&#34;https://www.percona.com/blog/2021/04/29/improving-percona-monitoring-and-management-ec2-instance-resilience-using-cloudwatch-alarm-actions/&#34;&gt;&lt;/a&gt;is outdated: Cloudwatch metrics are available for both types of check failures and people have set up &lt;a href=&#34;https://www.percona.com/blog/2021/04/29/improving-percona-monitoring-and-management-ec2-instance-resilience-using-cloudwatch-alarm-actions/&#34;&gt;&lt;/a&gt;recovery for both types of failures &lt;a href=&#34;https://www.percona.com/blog/2021/04/29/improving-percona-monitoring-and-management-ec2-instance-resilience-using-cloudwatch-alarm-actions/&#34;&gt;using AWS CLI&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform Azure resource provider registration fails</title>
				<link>https://www.puppeteers.net/blog/terraform-azure-resource-provider-registration-fails/</link>
				<pubDate>Tue, 26 Oct 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-azure-resource-provider-registration-fails/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.terraform.io/&#34;&gt;Terraform&lt;/a&gt; has good support for &lt;a href=&#34;https://azure.microsoft.com/en-us/&#34;&gt;Microsoft Azure&lt;/a&gt; through the &lt;a href=&#34;https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs&#34;&gt;Terraform Azure provider&lt;/a&gt; and the &lt;a href=&#34;https://www.terraform.io/docs/language/settings/backends/azurerm.html&#34;&gt;AzureRM backend&lt;/a&gt;. However, you may hit a glitch when adding or importing resources if you lack permissions to register Azure resource providers:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;│ Error: Error ensuring Resource Providers are registered.&#xA;|&#xA;│ Terraform automatically attempts to register the Resource Providers it supports&#xA;| to ensure it&amp;#39;s able to provision resources.&#xA;│                                                                                                                                                                                   &#xA;│ If you don&amp;#39;t have permission to register Resource Providers you may wish to use&#xA;| the &amp;#34;skip_provider_registration&amp;#34; flag in the Provider block to disable this&#xA;| functionality.&#xA;│                                                                                                                                                                                   &#xA;│ Please note that if you opt out of Resource Provider Registration and Terraform&#xA;| tries to provision a resource from a Resource Provider which is unregistered,&#xA;| then the error may appear misleading - for example&#xA;|                                                                                                                                                                                   &#xA;│ &amp;gt; API version 2019-XX-XX was not found for Microsoft.Foo&#xA;|                                                                                                                                                                                   &#xA;│ Could indicate either that the Resource Provider &amp;#34;Microsoft.Foo&amp;#34; requires&#xA;| registration, but this could also indicate that this Azure Region doesn&amp;#39;t support | this API version.&#xA;|&#xA;│ More information on the &amp;#34;skip_provider_registration&amp;#34; flag can be found here:&#xA;|&#xA;│ https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs#skip_provider_registration&#xA;│&#xA;│ Original Error: Cannnot register providers: Microsoft.DataLakeAnalytics, Microsoft.DBforPostgreSQL, Microsoft.AVS, Microsoft.Media, Microsoft.ApiManagement, Microsoft.Search, Mic&#xA;rosoft.Maintenance, Microsoft.ServiceBus, Microsoft.HealthcareApis, Microsoft.Relay, Microsoft.DesktopVirtualization, Microsoft.NotificationHubs, Microsoft.SecurityInsights, Micros&#xA;oft.DBforMariaDB, Microsoft.Kusto, Microsoft.DataLakeStore, Microsoft.Automation, Microsoft.CognitiveServices, Microsoft.ManagedServices, Microsoft.EventGrid, Microsoft.BotService,&#xA;&#xA;--- snip ---&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;At first glance this error look cryptic, but it is quite clear once you understand &lt;a href=&#34;https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types&#34;&gt;what Azure resource providers are&lt;/a&gt; - I like to think of them as &lt;em&gt;&amp;ldquo;enabled Azure services&amp;rdquo;&lt;/em&gt; or &lt;em&gt;&amp;ldquo;enabled Azure features&amp;rdquo;&lt;/em&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>OpenVPN server options in Azure</title>
				<link>https://www.puppeteers.net/blog/openvpn-server-options-in-azure/</link>
				<pubDate>Thu, 21 Oct 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/openvpn-server-options-in-azure/</guid>
				<description>&lt;p&gt;OpenVPN is among the best VPN solutions, especially when you need a cross-platform (Windows, Mac, Linux, Android, iOS) solution that just works. It is best suited for point to site (P2S) or &amp;ldquo;road warrior&amp;rdquo; setups where users access internal resources using a VPN client when on the road.&lt;/p&gt;&#xA;&lt;p&gt;When setting up OpenVPN server in Azure you have several options at your disposal:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Set up your own open source &lt;a href=&#34;https://github.com/OpenVPN/openvpn&#34;&gt;OpenVPN 2&lt;/a&gt; server&lt;/p&gt;</description>
			</item>
			<item>
				<title>Recruiting for a small business - lessons learned, part 2: Tips for job seekers</title>
				<link>https://www.puppeteers.net/blog/recruiting-for-a-small-business-lessons-learned-part-2-tips-for-job-seekers/</link>
				<pubDate>Fri, 20 Aug 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/recruiting-for-a-small-business-lessons-learned-part-2-tips-for-job-seekers/</guid>
				<description>&lt;p&gt;I previously wrote about takeaways from our first recruitment process as a recruiter in January 2021. This time I’m looking back to the recruitment process in order to gather tips for the other half, job applicants and seekers. Part of the advice are also based on my own experiences as a job seeker and some even on common sense. A recruiter of a bigger company could formulate this article a bit differently but these aspects mattered to us, as a small business.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Poor marketing, part #1</title>
				<link>https://www.puppeteers.net/blog/poor-marketing-part-1/</link>
				<pubDate>Tue, 10 Aug 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/poor-marketing-part-1/</guid>
				<description>&lt;p&gt;As an entrepreneur you are flooded with attempts to persuade you to buy something. Typically what is sold is services like website development, mobile application development or outsourced developer/devops workforce. Most attempts are mediocre, but only a few can be classified as outright bad. As inbound marketing and sales are dear to our heart, in this series we present some of the worst marketing attempts we&amp;rsquo;ve seen, in the order of appearance. We try to add some value by adding a humoristic analysis on top. All the names and emails have been converted to John or Jane Doe and example.org so that you don&amp;rsquo;t accidentally buy anything from these guys. However, with pinch of luck you may find the exact same message in &lt;em&gt;your&lt;/em&gt; INBOX if you feel the urge to buy something from these guys.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Software release: net-snmp-systemd-services-status</title>
				<link>https://www.puppeteers.net/blog/software-release-net-snmp-systemd-services-status/</link>
				<pubDate>Fri, 06 Aug 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/software-release-net-snmp-systemd-services-status/</guid>
				<description>&lt;p&gt;Puppeteers is proud to release the first version of &lt;a href=&#34;https://github.com/Puppet-Finland/net-snmp-systemd-service-status&#34;&gt;net-snmp-systemd-services-status&lt;/a&gt;. It is a &lt;a href=&#34;https://net-snmp.sourceforge.io/&#34;&gt;net-snmp&lt;/a&gt; pass_persist script written in Python that queries the status of all systemd services on a system, dynamically generating OIDs based on the systemd service names. This gives the services a predictable name. Querying all services on a typical Linux VM takes less than 0.2 seconds. The information is presented to snmpd in a way that both get (snmpget) and getnext (snmpwalk) work.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Extending snmpd with custom scripts</title>
				<link>https://www.puppeteers.net/blog/extending-snmpd-with-custom-scripts/</link>
				<pubDate>Fri, 16 Jul 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/extending-snmpd-with-custom-scripts/</guid>
				<description>&lt;p&gt;Traditional network monitoring systems tend to get their monitoring data via SNMP. In case of Linux snmpd is usually the system application that&amp;rsquo;s responsible for providing that data. The data consists mostly, but not entirely, of metrics. For example, the data contains strings such as operating system version, administrative contacts and network interface names.&lt;/p&gt;&#xA;&lt;p&gt;It is possible to make snmpd run custom scripts and programs to gather more data from the system. The options are described in &lt;a href=&#34;http://www.net-snmp.org/docs/man/snmpd.conf.html&#34;&gt;snmpd.conf man page&lt;/a&gt;, but here are the most important ones for this use-case:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Making modals responsive in Oxygen Builder for Wordpress</title>
				<link>https://www.puppeteers.net/blog/making-modals-responsive-in-oxygen-builder-for-wordpress/</link>
				<pubDate>Wed, 14 Jul 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-modals-responsive-in-oxygen-builder-for-wordpress/</guid>
				<description>&lt;p&gt;I always thought that it would be impossible for me to make convincing looking websites. But I did learn it and enjoy it very much. But as soon as I’m ready with a new, beautiful web page on my screen, my joy is cut short by the fact that I still need to make it responsive. Learning website development is in fact a double battle: first learning the techniques to make nice things on a web page, and then learning another set of techniques on how to keep the design beautiful on smaller screens. In my experience, the latter battle is way bigger, and thus hope that sharing the lesson I learned will save someone from the agony I had to go through. I’ll focus on modals because making them responsive has been the toughest part for me.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Packer QEMU performance: speed things up with two-stage builds</title>
				<link>https://www.puppeteers.net/blog/two-stage-qemu-builds-with-packer/</link>
				<pubDate>Thu, 08 Jul 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/two-stage-qemu-builds-with-packer/</guid>
				<description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;In the &amp;ldquo;&lt;a href=&#34;https://www.puppeteers.net/blog/building-ubuntu-20-04-qemu-images-with-packer/&#34;&gt;Packer QEMU: Building Ubuntu 20.04/22.04/24.04 VM images&lt;/a&gt;&amp;rdquo; blog post we briefly mentioned ways to improve Packer QEMU performance. In this article we&amp;rsquo;ll go into the details on how this is implemented. The key in improving Packer QEMU performance is to split the build into two distinct stages:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Operating system installation stage&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Provisioning stage&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;This setup cuts down development time considerably as repeating the provisioning stage becomes a lot faster.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Packer QEMU: Building Ubuntu 20.04/22.04/24.04 VM images</title>
				<link>https://www.puppeteers.net/blog/building-ubuntu-20-04-qemu-images-with-packer/</link>
				<pubDate>Mon, 05 Jul 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/building-ubuntu-20-04-qemu-images-with-packer/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-karolina-grabowska-44981361-683x1024.jpg&#34; alt=&#34;A person closing a large cardboard box with tape.&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://developer.hashicorp.com/packer/integrations/hashicorp/qemu/latest/components/builder/qemu&#34;&gt;Packer QEMU builder&lt;/a&gt; allows you to build virtual machine images from scratch. You need a &lt;em&gt;Packerfile&lt;/em&gt;, an &lt;em&gt;automatic installation configuration file&lt;/em&gt; (autoinstall, kickstart or preseed) and the &lt;em&gt;operating system installer&lt;/em&gt; (e.g. ISO). The benefit of Packer QEMU in particular are that you can have fine-grained control over the virtual machine image content such as disk partitioning. Moreover you don&amp;rsquo;t need to rely on official base images produced by other people, such as the official &lt;a href=&#34;https://cloud-images.ubuntu.com/&#34;&gt;Ubuntu Cloud images&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Creating Puppet Bolt groups based on AWS tags</title>
				<link>https://www.puppeteers.net/blog/creating-puppet-bolt-groups-based-on-aws-tags/</link>
				<pubDate>Thu, 01 Jul 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/creating-puppet-bolt-groups-based-on-aws-tags/</guid>
				<description>&lt;p&gt;The &lt;a href=&#34;https://www.puppeteers.net/blog/using-tags-in-puppet-bolt-aws_inventory-target_mapping/&#34;&gt;Using tags in Puppet Bolt aws_inventory target_mapping&lt;/a&gt; showed how to use AWS &amp;ldquo;Name&amp;rdquo; tag as the target name for Puppet Bolt. Use of tags can be extended to creating Bolt target groups:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;groups:&#xA;  - name: webservers&#xA;    targets:&#xA;     - _plugin: aws_inventory&#xA;       region:&#xA;         _plugin: env_var&#xA;         var: AWS_DEFAULT_REGION&#xA;       filters:&#xA;         - name: tag:Type&#xA;           values: [webserver]&#xA;       target_mapping:&#xA;         name: tags.Name&#xA;         uri: public_ip_address&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;All you need to do is add a &amp;ldquo;filter&amp;rdquo; section with one filter. The &amp;ldquo;name&amp;rdquo; parameter tells Bolt that the filter is based on tags and what tag to look for. The &amp;ldquo;Type&amp;rdquo; that follows &amp;ldquo;tag&amp;rdquo; is the name of the tag you want to filter by. The &amp;ldquo;values&amp;rdquo; array lists acceptable values for that tag. Any nodes that don&amp;rsquo;t have the tag (here: &amp;ldquo;Type&amp;rdquo;) or where tag value is not acceptable (e.g. &amp;ldquo;db&amp;rdquo;) will not be shown in the group.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Making wpcal.io work with Zimbra calendars</title>
				<link>https://www.puppeteers.net/blog/making-wpcal-io-work-with-zimbra-calendars/</link>
				<pubDate>Thu, 01 Jul 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-wpcal-io-work-with-zimbra-calendars/</guid>
				<description>&lt;p&gt;Scheduling meetings with email is annoying. When everyone is on the same timezone that kind of works, but tends to be slow. When you factor in timezone differences the process becomes really error-prone and slows down even more, often to several days. For this reason we wanted to provide people - including our customers - a way to easily schedule meetings with us.&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;re special in the sense that we self-host almost everything we use. For email and calendars we use &lt;a href=&#34;https://www.zimbra.com/&#34;&gt;Zimbra&lt;/a&gt; and for our website we use &lt;a href=&#34;https://wordpress.com/&#34;&gt;Wordpress&lt;/a&gt;. Most people seem to use &lt;a href=&#34;https://calendly.com/&#34;&gt;Calendly&lt;/a&gt; as a meeting scheduler, but we ended up choosing &lt;a href=&#34;https://wpcal.io/&#34;&gt;wpcal.io&lt;/a&gt; which is a native Wordpress plugin and seems to work quite nicely.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Testing Puppet feature environments with Puppet Bolt</title>
				<link>https://www.puppeteers.net/blog/testing-puppet-feature-environments-with-puppet-bolt/</link>
				<pubDate>Fri, 18 Jun 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/testing-puppet-feature-environments-with-puppet-bolt/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-workflow-part-2-r10k/&#34;&gt;Puppet feature environments&lt;/a&gt; are an excellent way to test code before deploying it, typically to production. They allow testing Puppet runs on no-operation mode across the whole node population managed by Puppet. There are sometimes cases where your code changes potentially impact many nodes and you&amp;rsquo;re not exactly sure of their scope or effect. In that case it helps to test your code on all Puppet-managed nodes. The challenge is that Puppet open source does not have any built-in mechanism to do that. This is where we can make good use of Puppet Bolt.&lt;/p&gt;</description>
			</item>
			<item>
				<title>To containerize in AWS or not: the cost perspective</title>
				<link>https://www.puppeteers.net/blog/to-containerize-in-aws-or-not-the-cost-perspective/</link>
				<pubDate>Tue, 15 Jun 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/to-containerize-in-aws-or-not-the-cost-perspective/</guid>
				<description>&lt;p&gt;I recently checked the pricing model for &lt;a href=&#34;https://aws.amazon.com/fargate/?nc=sn&amp;amp;loc=1&amp;amp;whats-new-cards.sort-by=item.additionalFields.postDateTime&amp;amp;whats-new-cards.sort-order=desc&amp;amp;fargate-blogs.sort-by=item.additionalFields.createdDate&amp;amp;fargate-blogs.sort-order=desc&#34;&gt;Amazon Fargate&lt;/a&gt; to see if migrating a fair number of EC2 instance-based workloads to containers would save money. In theory this should have been the case, as a container has less &amp;ldquo;fat&amp;rdquo; compared to a full virtual machine. In this case the workload itself was perfectly suited for a container: a single process with single configuration file that was mostly network-bound running on t3.micro instances.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using xfreerdp with Vagrant</title>
				<link>https://www.puppeteers.net/blog/using-xfreerdp-with-vagrant/</link>
				<pubDate>Tue, 15 Jun 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-xfreerdp-with-vagrant/</guid>
				<description>&lt;p&gt;Vagrant has built-in support for connecting to Windows VMs using the &lt;a href=&#34;https://www.vagrantup.com/docs/cli/rdp&#34;&gt;vagrant rdp command&lt;/a&gt;. It does basically does the same as &lt;a href=&#34;https://www.vagrantup.com/docs/cli/ssh&#34;&gt;vagrant ssh&lt;/a&gt; for Linux VMs. There are a few shortcomings, though: vagrant rdp fails to automatically accept the host key of the VM it is connecting to, at least when using it from Linux with xfreerdp. So, you first need to connect to the VM directly once with raw xfreerdp, then vagrant rdp will start working. Then, when you wipe out the VM, you need to repeat the process again. If you have a high resolution screen you will also notice that vagrant rdp will give you a tiny Windows desktop where you need a magnifying glass to read the text.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Installing individual components to Visual Studio 2019 from the command-line</title>
				<link>https://www.puppeteers.net/blog/installing-individual-components-to-visual-studio-2019-from-the-command-line/</link>
				<pubDate>Mon, 07 Jun 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/installing-individual-components-to-visual-studio-2019-from-the-command-line/</guid>
				<description>&lt;p&gt;I&amp;rsquo;ve been doing lots of Windows automation recently. My goal has been to be able to reproducibly create a Windows Server 2019-based &lt;a href=&#34;http://buildbot.net/&#34;&gt;Buildbot&lt;/a&gt; workers, first in a &lt;a href=&#34;https://www.vagrantup.com/&#34;&gt;Vagrant&lt;/a&gt; environment, then later in AWS EC2 using pre-built images created with &lt;a href=&#34;https://www.packer.io/&#34;&gt;Packer&lt;/a&gt;. This task requires installing Visual Studio 2019 build tools automatically and fetching the project&amp;rsquo;s dependencies with &lt;a href=&#34;https://vcpkg.io/en/index.html&#34;&gt;vcpkg&lt;/a&gt; automatically. It is possible to install Visual Studio 2019 with &lt;a href=&#34;https://community.chocolatey.org/packages/visualstudio2019buildtools&#34;&gt;Chocolatey&lt;/a&gt; quite easily, but what if you need to install additional components to Visual Studio without using the Visual Studio installer GUI? Looking around did not quickly reveal any de facto instructions on how to do it, so this article aims to fill that gap.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using tags in Puppet Bolt aws_inventory target_mapping</title>
				<link>https://www.puppeteers.net/blog/using-tags-in-puppet-bolt-aws_inventory-target_mapping/</link>
				<pubDate>Sat, 05 Jun 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-tags-in-puppet-bolt-aws_inventory-target_mapping/</guid>
				<description>&lt;p&gt;We&amp;rsquo;re migrating away from Ansible to Puppet Bolt and the fact that Ansible updates broke the old &lt;a href=&#34;https://github.com/ansible/ansible/blob/stable-2.9/contrib/inventory/ec2.py&#34;&gt;ec2.py inventory script&lt;/a&gt; expedited that process. While that inventory script was quite rudimentary, it was able to automatically add human-readable names to the EC2 instance names. So, for example, you could target a node using &amp;ldquo;server_example_org&amp;rdquo; if the Name tag was set to &amp;ldquo;server.example.org&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;Puppet Bolt&amp;rsquo;s &lt;a href=&#34;https://github.com/puppetlabs/puppetlabs-aws_inventory&#34;&gt;aws_inventory&lt;/a&gt; &lt;em&gt;seemed&lt;/em&gt; to lack that feature, but after taking a good look at its code this was just a case of missing documentation, which I fixed in &lt;a href=&#34;https://github.com/puppetlabs/puppetlabs-aws_inventory/pull/19&#34;&gt;this PR&lt;/a&gt;. Here&amp;rsquo;s an example of &lt;em&gt;inventory.yaml&lt;/em&gt; for Bolt that maps the value of the &amp;ldquo;Name&amp;rdquo; tag to the name of the Bolt target:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Making Vagrant work on Fedora 34</title>
				<link>https://www.puppeteers.net/blog/making-vagrant-work-on-fedora-34/</link>
				<pubDate>Tue, 01 Jun 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-vagrant-work-on-fedora-34/</guid>
				<description>&lt;p&gt;We use Vagrant and Virtualbox a lot because it is an excellent tool for infrastructure code development. Unfortunately it is also very prone to breakage during operating system upgrades, especially if you depend on many plugins. When I upgraded from Fedora 32 to 34 Vagrant broken even more than usual due to conflicting rspec dependencies. Basically every Vagrant plugin refused to install with this error message:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ vagrant plugin install vagrant-vbguest&#xA;Installing the &amp;#39;vagrant-vbguest&amp;#39; plugin. This can take a few minutes...&#xA;&#xA;Vagrant failed to properly resolve required dependencies. These&#xA;errors can commonly be caused by misconfigured plugin installations&#xA;or transient network issues. The reported error is:&#xA;&#xA;conflicting dependencies rspec (= 3.10.0) and rspec (= 2.14.1)&#xA;  Activated rspec-2.14.1&#xA;  which does not match conflicting dependency (= 3.10.0)&#xA;&#xA;  Conflicting dependency chains:&#xA;    rspec (= 2.14.1), 2.14.1 activated&#xA;&#xA;  versus:&#xA;    rspec (= 3.10.0)&#xA;&#xA;  Gems matching rspec (= 3.10.0):&#xA;    rspec-3.10.0&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;The rspec dependency conflict does not sound particularly scary for somebody who is not &lt;em&gt;developing&lt;/em&gt; Vagrant or Vagrant plugins. Therefore ignoring the dependencies is likely to be just fine:&lt;/p&gt;</description>
			</item>
			<item>
				<title>What Vagrant plugins actually are?</title>
				<link>https://www.puppeteers.net/blog/what-vagrant-plugins-actually-are/</link>
				<pubDate>Tue, 01 Jun 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/what-vagrant-plugins-actually-are/</guid>
				<description>&lt;p&gt;This was a revelation that came to me &lt;a href=&#34;https://www.puppeteers.net/blog/making-vagrant-work-on-fedora-34/&#34;&gt;when fixing Vagrant on my Fedora 34 laptop&lt;/a&gt;: Vagrant plugins seem to be just Ruby gems installed into an isolated runtime environment, with &amp;ldquo;vagrant plugin&amp;rdquo; ensuring that the gems are installed in the correct place.&lt;/p&gt;&#xA;&lt;p&gt;The same gems that you can install with &amp;ldquo;vagrant plugiin install&amp;rdquo; can be found using vanilla gem command:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ vagrant plugin list&#xA;rexml (3.2.5, global)&#xA;vagrant-hostmanager (1.8.9, global)&#xA;vagrant-vbguest (0.29.0, global)&#xA;winrm (2.3.6, global)&#xA;winrm-elevated (1.2.3, global)&#xA;winrm-fs (1.3.5, global)&#xA;&#xA;$ gem info --remote rexml&#xA;&#xA;*** REMOTE GEMS ***&#xA;&#xA;rexml (3.2.5)&#xA;    Author: Kouhei Sutou&#xA;    Homepage: https://github.com/ruby/rexml&#xA;&#xA;    An XML toolkit for Ruby&#xA;&#xA;$ gem info --remote vagrant-vbguest&#xA;&#xA;*** REMOTE GEMS ***&#xA;&#xA;vagrant-vbguest (0.29.0)&#xA;    Author: Robert Schulze&#xA;    Homepage: https://github.com/dotless-de/vagrant-vbguest&#xA;&#xA;    A Vagrant plugin to install the VirtualBoxAdditions into the guest&#xA;    VM&#xA;&#xA;$ gem list|grep vagrant&#xA;&amp;lt;no output&amp;gt;&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;On the remote side you can find all the familiar Vagrant plugins as gems, but vanilla gem won&amp;rsquo;t find them installed locally, because they&amp;rsquo;re in a different path.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet types and providers development part 5: self.instances</title>
				<link>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-5-self-instances/</link>
				<pubDate>Sun, 30 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-5-self-instances/</guid>
				<description>&lt;p&gt;This blog post is a part of this blog post series:&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://www.rubydoc.info/gems/puppet/Puppet%2FProvider.instances&#34;&gt;self.instances&lt;/a&gt; is a provider class method that is used to produce an array containing all resources found from the system. For example, a yum package provider might run &amp;ldquo;rpm -qa&amp;rdquo; in self.instances to get a list of packages installed on the system. This serves two main purposes:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Allows using of &amp;ldquo;puppet resource type&amp;rdquo; to produce Puppet code for all resources of type found on the system.&lt;/li&gt;&#xA;&lt;li&gt;Data created by self.instances can be passed to &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-6-mysteries-of-self-prefetch/&#34;&gt;self.prefetch&lt;/a&gt; to cache resource properties. The cached properties are then reused for every resource of that provider type. For example, a yum package provider might create a list of packages installed on a system when Puppet encounters the first &amp;ldquo;yum&amp;rdquo; package resource of &amp;ldquo;yum&amp;rdquo; type. That cache would then be reused, thus removing the need to individually check each package&amp;rsquo;s state.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;As discussed in &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-4-caching-resource-properties-to-improve-performance/&#34;&gt;Puppet types and providers development part 4: caching resource properties to improve performance&lt;/a&gt; self.instances or self.prefetch are not really suitable for scenarios where you need to manage (multiple) remote systems using the same provider, because things like connection would be given in the Puppet resource definition are at the provider instance level, to which provider class level methods like self.instance and self.prefetch do not have access to.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet types and providers development part 6: mysteries of self.prefetch</title>
				<link>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-6-mysteries-of-self-prefetch/</link>
				<pubDate>Sun, 30 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-6-mysteries-of-self-prefetch/</guid>
				<description>&lt;p&gt;This blog post is a part of this blog post series:&lt;/p&gt;&#xA;&lt;p&gt;I will open this blog post with a quote from the famous Gary Larizza:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;After wading the waters of &lt;code&gt;self.prefetch&lt;/code&gt;, I’m PRETTY SURE its implementation might have come to uncle Luke after a long night in Reed’s chem lab where he might have accidently synthesized mescaline.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;http://garylarizza.com/blog/2013/12/15/seriously-what-is-this-provider-doing/&#34;&gt;http://garylarizza.com/blog/2013/12/15/seriously-what-is-this-provider-doing/&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;After reading Gary&amp;rsquo;s rather elaborate explanation about self.prefetch I still did not fully get what self.prefetch &lt;em&gt;actually&lt;/em&gt; does and the official documentation surely does not help:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Limiting concurrent builds in Buildbot</title>
				<link>https://www.puppeteers.net/blog/limiting-concurrent-builds-in-buildbot/</link>
				<pubDate>Fri, 21 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/limiting-concurrent-builds-in-buildbot/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;http://buildbot.net/&#34;&gt;Buildbot&lt;/a&gt; is a continuous integration &lt;em&gt;framework&lt;/em&gt; which many open source projects seem to be using. Unlike continuous integration &lt;em&gt;applications&lt;/em&gt; or &lt;em&gt;automation servers&lt;/em&gt; like &lt;a href=&#34;https://www.jenkins.io/&#34;&gt;Jenkins&lt;/a&gt; Buildbot does not make many assumptions about your use-case. In fact, when you build your CI or CD pipeline you&amp;rsquo;re actually writing Python code and hence have all the flexibility of Python directly at your disposal. In other words, you&amp;rsquo;re not being blocked or obstructed by assumptions hidden in the tool itself, like often tends to happen with Jenkins.&lt;/p&gt;</description>
			</item>
			<item>
				<title>How to Setup a Staging Wordpress Server</title>
				<link>https://www.puppeteers.net/blog/how-to-staging-wordpress/</link>
				<pubDate>Tue, 18 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/how-to-staging-wordpress/</guid>
				<description>&lt;p&gt;Having a staging server for Wordpress is quite useful for testing new features without the worry of breaking something in production. It is also helpful when you have a multi user environment and need to test something that could impact others. In this article it is assumed that your Wordpress instance has SELinux enabled as is the case on RHEL/CentOS for example. On other distros like Ubuntu or Debian you can omit the steps specific to SELinux.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Managing self-hosted GitLab with Terraform</title>
				<link>https://www.puppeteers.net/blog/managing-self-hosted-gitlab-with-terraform/</link>
				<pubDate>Sun, 16 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/managing-self-hosted-gitlab-with-terraform/</guid>
				<description>&lt;p&gt;GitLab has an &lt;a href=&#34;https://docs.gitlab.com/ee/api/&#34;&gt;extensive API&lt;/a&gt; which allows managing its internal configuration such as users, groups and projects. The official &lt;a href=&#34;https://registry.terraform.io/providers/gitlabhq/gitlab/latest&#34;&gt;GitLab Terraform provider&lt;/a&gt; builds on top of this API.&lt;/p&gt;&#xA;&lt;p&gt;It assumed here that the Terraform controller (e.g. your laptop) is able to reach your GitLab instance&amp;rsquo;s TCP port 443 - if it can&amp;rsquo;t there&amp;rsquo;s no way Terraform&amp;rsquo;s API calls will work. The same approach should work with gitlab.com - you can probably (=untested) skip the base_url parameter in that case.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Delegating external parties access to AWS</title>
				<link>https://www.puppeteers.net/blog/delegating-external-parties-access-to-aws/</link>
				<pubDate>Fri, 14 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/delegating-external-parties-access-to-aws/</guid>
				<description>&lt;p&gt;This blog post shows how to grant access to an AWS account for some external party. For simplicity we will call this external party a &amp;ldquo;contractor&amp;rdquo;. If you want to do the same for Microsoft Azure look at &lt;a href=&#34;https://www.puppeteers.net/blog/delegating-external-parties-access-to-azure/&#34;&gt;this blog post&lt;/a&gt; instead.&lt;/p&gt;&#xA;&lt;p&gt;This method requires the contractor to have its own AWS account, but it has several benefits:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;No need to create AWS user accounts for every single person working for the contractor&lt;/li&gt;&#xA;&lt;li&gt;You can force the contractor&amp;rsquo;s personnel to use two-factor authentication (2FA)&lt;/li&gt;&#xA;&lt;li&gt;You can force the contractor to use an additional password (shared secret)&lt;/li&gt;&#xA;&lt;li&gt;You can disable contractor&amp;rsquo;s access completely by just removing the IAM role&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This approach works equally well for AWS Console access, AWS CLI and tools like Terraform. Some tools may not like the extra security measures required here or be able to assume a role out of the box.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Delegating external parties access to Azure</title>
				<link>https://www.puppeteers.net/blog/delegating-external-parties-access-to-azure/</link>
				<pubDate>Fri, 14 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/delegating-external-parties-access-to-azure/</guid>
				<description>&lt;p&gt;In &lt;a href=&#34;https://azure.microsoft.com/&#34;&gt;Microsoft Azure&lt;/a&gt; you can grant an external user (&amp;ldquo;contractor&amp;rdquo;) guest access to your Azure subscription. The approach is quite different from what &lt;a href=&#34;https://aws.amazon.com&#34;&gt;AWS&lt;/a&gt; uses (see &lt;a href=&#34;https://www.puppeteers.net/blog/delegating-external-parties-access-to-aws/&#34;&gt;Delegating external parties access to AWS&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Here we grant access to &lt;em&gt;john.doe@contoso.com&lt;/em&gt; using the Azure Portal. Preferably &lt;em&gt;john.doe@contoso.com&lt;/em&gt; would already exist as a Microsoft account.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Login to your Azure Portal&lt;/li&gt;&#xA;&lt;li&gt;Type &amp;ldquo;Users&amp;rdquo; in the search box&lt;/li&gt;&#xA;&lt;li&gt;Click on the &amp;ldquo;Users&amp;rdquo; service&lt;/li&gt;&#xA;&lt;li&gt;Click on &amp;ldquo;New guest user&amp;rdquo;&lt;/li&gt;&#xA;&lt;li&gt;Select &amp;ldquo;Invite User&amp;rdquo;&lt;/li&gt;&#xA;&lt;li&gt;Fill in the fields. The email address should be the one given by the external user.&lt;/li&gt;&#xA;&lt;li&gt;Click on &amp;ldquo;Invite&amp;rdquo; at the bottom&lt;/li&gt;&#xA;&lt;li&gt;The external user will receive an invite to your Azure in the email address you defined above.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Now the user has been created. However, it is lacking permissions to do anything useful. We will fix that in the next steps by assigning it a role:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Dynamic partitioning in Foreman kickstart templates</title>
				<link>https://www.puppeteers.net/blog/dynamic-partitioning-in-foreman-kickstart-templates/</link>
				<pubDate>Wed, 12 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/dynamic-partitioning-in-foreman-kickstart-templates/</guid>
				<description>&lt;p&gt;Foreman&amp;rsquo;s &lt;a href=&#34;https://docs.theforeman.org/nightly/Provisioning_Guide/index-foreman-deb.html&#34;&gt;provisioning system&lt;/a&gt; allows creating provisioning templates with highly dynamic content. This article describes how to create dynamic content in your Foreman provisioning templates. While the example is related to dynamic partitioning in kickstart, the basic mechanisms for setting this up applies to any kind of template.&lt;/p&gt;&#xA;&lt;p&gt;Foreman &lt;a href=&#34;https://docs.theforeman.org/nightly/Provisioning_Guide/index-foreman-deb.html#provisioning-templates_provisioning&#34;&gt;provisioning templates&lt;/a&gt; are written in &lt;a href=&#34;https://www.stuartellis.name/articles/erb/&#34;&gt;ERB format&lt;/a&gt;. This allows having logic in the template itself based on user-defined host parameters. For example the &lt;a href=&#34;https://github.com/theforeman/foreman/blob/develop/app/views/unattended/provisioning_templates/provision/kickstart_default.erb&#34;&gt;Kickstart default template&lt;/a&gt; consumes a bunch of &lt;a href=&#34;https://docs.theforeman.org/nightly/Managing_Hosts/index-foreman-el.html&#34;&gt;host parameters&lt;/a&gt; that allow you to define what kind of kickstart file you want Foreman to spit out for each host or host group. To give a simple example there&amp;rsquo;s the &amp;ldquo;lang&amp;rdquo; parameter which sets the value for &amp;ldquo;lang&amp;rdquo; kickstart option:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Gitlab SAML to Keycloak Setup</title>
				<link>https://www.puppeteers.net/blog/gitlab-saml-with-keycloak/</link>
				<pubDate>Wed, 12 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/gitlab-saml-with-keycloak/</guid>
				<description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Integrating Keycloak with Gitlab SAML makes it easier to manage users in an organization from a central point. You could manage separate accounts on Gitlab, but for us it makes sense to utilize Keycloak as we are already using it for other applications.&lt;/p&gt;&#xA;&lt;h2 id=&#34;setting-up-keycloak&#34;&gt;Setting up Keycloak&lt;/h2&gt;&#xA;&lt;p&gt;The first step is to create a Gitlab SAML client in the Keycloak dashboard. With the correct realm selected, navigate to the Clients configuration page and click the create button to add a new client.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Microsoft Teams redirect loop mystery</title>
				<link>https://www.puppeteers.net/blog/microsoft-teams-redirect-loop-mystery/</link>
				<pubDate>Tue, 11 May 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/microsoft-teams-redirect-loop-mystery/</guid>
				<description>&lt;p&gt;Some of our customers use Microsoft&amp;rsquo;s Office 365. Due to that they also use Microsoft Teams for collaboration. Recently, out of the blue, I ran into a &amp;ldquo;redirect loop mystery&amp;rdquo; in Teams. Basically I was able to login to &lt;em&gt;our&lt;/em&gt; Teams (which we only use when recording video calls). But when I tried to switch to a customer workspace I was able to get in, but got immediately redirected back to our own workspace. This issue affected both the official Teams client for Linux, as well as the Chrome browser. Fortunately this was a well-known issue that could be fixed by &lt;a href=&#34;https://docs.microsoft.com/en-us/microsoftteams/troubleshoot/teams-sign-in/sign-in-loop#resolution&#34;&gt;relaxing cookie security settings&lt;/a&gt; in the browser.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Cutting down Azure storage costs for a Marketplace seller</title>
				<link>https://www.puppeteers.net/blog/cutting-down-azure-storage-costs-for-a-marketplace-seller/</link>
				<pubDate>Mon, 19 Apr 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/cutting-down-azure-storage-costs-for-a-marketplace-seller/</guid>
				<description>&lt;p&gt;A few days ago I looked at our Azure costs and they were around $8. That&amp;rsquo;s a ridiculously small amount, except for the fact that we don&amp;rsquo;t really &lt;em&gt;use&lt;/em&gt; Azure for anything. So I started investigating.&lt;/p&gt;&#xA;&lt;p&gt;After having published the Configuration Manager (Puppet master installer image) and LibreNMS in Azure Marketplace I knew that we had a bunch of BLOBs lying around. I knew how to find these blobs using the Storage Explorer. So I tested wiping them all out, as I knew Azure does not delete them immediately, but only after one day. Then I attempted to launch Configuration Manager and LibreNMS from the Azure Marketplace GUI. My thought was that those blobs had already been copied elsewhere (for global distribution) and would not be used by the Marketplace anymore, but it &lt;em&gt;looked like&lt;/em&gt; I was wrong. At least I got odd behavior when trying to launch those images and reverting the blob deletion fixed things.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Making per-link DNS servers added by Wireguard to systemd-resolved survive NetworkManager connection changes</title>
				<link>https://www.puppeteers.net/blog/making-per-link-dns-servers-added-by-wireguard-to-systemd-resolved-survive-networkmanager-connection-changes/</link>
				<pubDate>Tue, 13 Apr 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-per-link-dns-servers-added-by-wireguard-to-systemd-resolved-survive-networkmanager-connection-changes/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; the problem described in this article seems to be resolved in Fedora 36 (NetworkManager 1.38.0-2.fc36). It is still present in Fedora 35 (NetworkManager 1.32.12-2.fc35).&lt;/p&gt;&#xA;&lt;p&gt;The title of this blog post may seem familiar to some, as &lt;a href=&#34;https://www.puppeteers.net/blog/making-per-link-dns-servers-pushed-from-openvpn-to-systemd-resolved-survive-networkmanager-connection-changes/&#34;&gt;I solved this problem&lt;/a&gt; for OpenVPN earlier. I won&amp;rsquo;t repeat myself here, so please check the &lt;a href=&#34;https://www.puppeteers.net/blog/making-per-link-dns-servers-pushed-from-openvpn-to-systemd-resolved-survive-networkmanager-connection-changes/&#34;&gt;OpenVPN article&lt;/a&gt; to understand why this is happening.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.wireguard.com/&#34;&gt;Wireguard&lt;/a&gt; servers - unlike &lt;a href=&#34;https://openvpn.net/community/&#34;&gt;OpenVPN&lt;/a&gt; servers - are not able to push any settings such as DNS servers to their clients. However, Wireguard client itself is able to run PostUp commands to configure per-link DNS. The same approach can be used with OpenVPN &amp;ldquo;up&amp;rdquo; scripts as well, if you prefer having full control at the client-side. Here&amp;rsquo;s a Wireguard example:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Product launch: &#39;Puppeteers Cloud Modeling&#39;</title>
				<link>https://www.puppeteers.net/blog/product-launch-puppeteers-cloud-modeling/</link>
				<pubDate>Tue, 13 Apr 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/product-launch-puppeteers-cloud-modeling/</guid>
				<description>&lt;p&gt;Puppeteers has launched a new service product which allows you to gain control of your Cloud resources by having them imported to Terraform. This allows you to manage changes to your Cloud and radically reduces the need for the pesky &amp;ldquo;who changes this and why?&amp;rdquo;, &amp;ldquo;who set this up and is it still needed?&amp;rdquo; and &amp;ldquo;what does it do?&amp;rdquo; discussions. As a bonus you get much better visibility into your cloud.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet Bolt: taking action based on exit codes</title>
				<link>https://www.puppeteers.net/blog/puppet-bolt-taking-action-based-on-exit-codes/</link>
				<pubDate>Tue, 13 Apr 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-bolt-taking-action-based-on-exit-codes/</guid>
				<description>&lt;p&gt;Puppet resources like Package, File or Service are idempotent. In other words, you define the state of the resource and Puppet enforces it. The resources can be used in Bolt plans as well, which frees you from having to do state checks yourself. However, if the thing you&amp;rsquo;re managing is not a Puppet resource you have to check its state manually and use that information to drive login in your plan. Here&amp;rsquo;s a crude but functional PoC for checking if a node&amp;rsquo;s certificate is present on the Puppetmaster and acting accordingly:&lt;/p&gt;</description>
			</item>
			<item>
				<title>The four ways to install Puppet modules</title>
				<link>https://www.puppeteers.net/blog/the-four-ways-to-install-puppet-modules/</link>
				<pubDate>Tue, 13 Apr 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/the-four-ways-to-install-puppet-modules/</guid>
				<description>&lt;p&gt;When working with Puppet and Puppet modules in particular you quickly notice that there are several ways to manage module dependencies. Today I learned about a &lt;em&gt;new&lt;/em&gt; way introduced in Puppet Bolt 3.x, so I thought I&amp;rsquo;d compile a list that celebrates this diversity:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://puppet.com/docs/puppet/7.5/modules_metadata.html&#34;&gt;metadata.json&lt;/a&gt;: used primarily to dependency metadata to &lt;a href=&#34;https://forge.puppet.com/&#34;&gt;Puppet Forge&lt;/a&gt;. Some tools like &lt;a href=&#34;https://github.com/voxpupuli/librarian-puppet&#34;&gt;librarian-puppet&lt;/a&gt; and &lt;a href=&#34;https://www.puppeteers.net/blog/tag/puppet-litmus/&#34;&gt;puppet-litmus&lt;/a&gt; use / can use this file to download dependency modules. The downside is that you can&amp;rsquo;t define the location of the modules, so you&amp;rsquo;re limited to Forge modules.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform stalls when recreating security groups</title>
				<link>https://www.puppeteers.net/blog/terraform-stalls-when-recreating-security-groups/</link>
				<pubDate>Tue, 23 Mar 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-stalls-when-recreating-security-groups/</guid>
				<description>&lt;p&gt;Sometimes Terraform stalls when trying to remove AWS EC2 security groups and Terraform does no give any hint as to what is wrong. The problem is caused by that security group being attached to an EC2 instance or network interface.&lt;/p&gt;&#xA;&lt;p&gt;Interestingly Terraform messes up the order of the AWS API calls even when it (attempts to) remove the security group &lt;em&gt;and&lt;/em&gt; detach it from all EC2 instances that use it. In other words, Terraform tries to remove the security group before it has been detached from the EC2 instances, which results in the stall:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppeteers webinar recording: Infrastructure as Code</title>
				<link>https://www.puppeteers.net/blog/puppeteers-webinar-recording-infrastructure-as-code/</link>
				<pubDate>Wed, 10 Mar 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppeteers-webinar-recording-infrastructure-as-code/</guid>
				<description>&lt;p&gt;Here&amp;rsquo;s a recording on our webinar on March 9, 2021:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=q4FHbed6GuY&#34;&gt;Infrastructure as Code&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;We covered the very basics of infrastructure as code, version control, quality assurance techniques and tools such as Puppet, Terraform, Ansible and Puppet Bolt.&lt;/p&gt;&#xA;&lt;p&gt;The webinar slides:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.net/wp-content/uploads/2021/03/Puppeteers-webinar-Infrastructure-as-Code-presentation-210309.pdf&#34;&gt;Puppeteers-webinar-Infrastructure-as-Code-presentation-210309&lt;/a&gt;&lt;a href=&#34;https://www.puppeteers.net/wp-content/uploads/2021/03/Puppeteers-webinar-Infrastructure-as-Code-presentation-210309.pdf&#34;&gt;Download&lt;/a&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Notes about puppet-litmus testing</title>
				<link>https://www.puppeteers.net/blog/notes-about-puppet-litmus-testing/</link>
				<pubDate>Sun, 07 Mar 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/notes-about-puppet-litmus-testing/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://puppetlabs.github.io/litmus/&#34;&gt;Puppet Litmus&lt;/a&gt; is a Puppet acceptance test harness that &lt;a href=&#34;https://puppetlabs.github.io/litmus/litmus-concepts.html&#34;&gt;leverages&lt;/a&gt; on many existing, proven technologies. In the long run Litmus aims to replace &lt;a href=&#34;https://github.com/voxpupuli/beaker&#34;&gt;Beaker&lt;/a&gt;. However, the latter is currently still the only way to run multi-machine (e.g. cluster) acceptance tests in a standardized way. For example we use Beaker for our Keycloak domain mode cluster tests &lt;a href=&#34;https://github.com/treydock/puppet-module-keycloak/blob/master/spec/acceptance/1_domain_mode_cluster_spec.rb&#34;&gt;in puppet-module-keycloak&lt;/a&gt;. On a high-level the test process is the same as with Beaker:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Provision the SUT (&amp;ldquo;System Under Test&amp;rdquo;)&lt;/p&gt;</description>
			</item>
			<item>
				<title>Passing Vagrant parameters to Puppet Litmus</title>
				<link>https://www.puppeteers.net/blog/passing-vagrant-parameters-to-puppet-litmus/</link>
				<pubDate>Sun, 07 Mar 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/passing-vagrant-parameters-to-puppet-litmus/</guid>
				<description>&lt;p&gt;Puppet Litmus allows creating SUTs (&amp;ldquo;System Under Test&amp;rdquo;) with Vagrant using Virtualbox or Hyper-V as the virtualization backend. However, the default virtual machine settings like 1024MB of memory are only suitable for very simple modules and applications. For example, Litmus testing our &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-puppetmaster&#34;&gt;puppetmaster-installer&lt;/a&gt; will fail with the default settings.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://puppetlabs.github.io/litmus/Litmus-core-commands.html&#34;&gt;Litmus documentation&lt;/a&gt; tells us that you can define parameters in provision.yaml which get then converted to environment variables. What it does not tell what to use these environment variables for. Looking at the Vagrant code in Litmus you can see that those environment variables can be used to drive the Virtualbox settings, among other things:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Recruiting for a small business - lessons learned, part 1: Tips for recruiters</title>
				<link>https://www.puppeteers.net/blog/recruiting-for-a-small-business-lessons-learned-part-1-tips-for-recruiters/</link>
				<pubDate>Thu, 04 Mar 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/recruiting-for-a-small-business-lessons-learned-part-1-tips-for-recruiters/</guid>
				<description>&lt;p&gt;Throw a job ad on a recruitment portal, wait for applications, hold a couple of interviews and that&amp;rsquo;s it, right? This is what recruiting can look like from the outside but there&amp;rsquo;s quite a bit more to it. A recruitment campaign can be a massive effort especially for small businesses. In addition, if you&amp;rsquo;re doing it for the first time, you may want some advice.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/pexels-cottonbro-5989925-683x1024.jpg&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;We&amp;rsquo;re a small company (with 3 more or less part-time employees) who recently ran our first official recruitment campaign so we know what we&amp;rsquo;re talking about! We hope that sharing our experiences will help other small businesses and organizations to get the most out of a recruitment campaign without losing too much time and money and building a good employer brand at the same time.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Fixing foreman-installer &#34;Forward DNS points to x&#34; errors</title>
				<link>https://www.puppeteers.net/blog/fixing-foreman-installer-forward-dns-points-to-errors/</link>
				<pubDate>Wed, 03 Mar 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fixing-foreman-installer-forward-dns-points-to-errors/</guid>
				<description>&lt;p&gt;This posting comes strictly from the land of esoteria. We have a &lt;a href=&#34;https://www.vagrantup.com/&#34;&gt;Vagrant&lt;/a&gt; + &lt;a href=&#34;https://www.virtualbox.org/&#34;&gt;Virtualbox&lt;/a&gt; environment that sets up &lt;a href=&#34;https://theforeman.org/&#34;&gt;Foreman&lt;/a&gt; used for &lt;a href=&#34;https://www.howtogeek.com/57601/what-is-network-booting-pxe-and-how-can-you-use-it/&#34;&gt;PXE booting&lt;/a&gt; baremetal servers. The environment work fine on Linux and MacOS. But we needed to make this environment work also on Windows. Easy, right? Vagrant and Virtualbox are supposed to abstract all those pesky operating system settings away, correct? After resolving a &lt;a href=&#34;https://www.puppeteers.net/blog/fixing-vagrant-vbguest-for-the-centos-7-base-box/&#34;&gt;non-Windows related challenge&lt;/a&gt; provisioning of Foreman on Windows almost worked. Except that it failed when foreman-installer attempted to start[*]. The error message was this:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Making vagrant-hostmanager UAC prompts go away on Windows</title>
				<link>https://www.puppeteers.net/blog/making-vagrant-hostmanager-uac-prompts-go-away-on-windows/</link>
				<pubDate>Wed, 03 Mar 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-vagrant-hostmanager-uac-prompts-go-away-on-windows/</guid>
				<description>&lt;p&gt;The &lt;a href=&#34;https://github.com/devopsgroup-io/vagrant-hostmanager&#34;&gt;vagrant-hostmanager&lt;/a&gt; plugin is a really nice plugin which helps Vagrant VMs communicate with each other using names instead of IP addresses. Essentially it manages hosts entries for the VMs, acting like a poor-man&amp;rsquo;s DNS. Now, on *NIX operating systems you typically use sudo, which caches your authorization. So, when hostmanager starts, you type your password once and then it is able to add all the host entries it needs to &lt;em&gt;/etc/hosts&lt;/em&gt;. This is not so on Windows: you will get one UAC prompt per modification to &lt;em&gt;c:\windows\system32\drivers\etc\hosts&lt;/em&gt;. This will eventually drive you crazy. To fix this you need to permit your Windows user account to modify the hosts-file without privilege elevation. To pull this off, you will need to modify that file&amp;rsquo;s access control lists. The process is quite convoluted imho, but here it goes:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Solving an Apache Mellon redirect loop mystery</title>
				<link>https://www.puppeteers.net/blog/solving-an-apache-mellon-redirect-loop-mystery/</link>
				<pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/solving-an-apache-mellon-redirect-loop-mystery/</guid>
				<description>&lt;p&gt;If you’re at all like me, you every now and then find yourself thrown out of your comfort zone, when you should actually be in it.&lt;/p&gt;&#xA;&lt;p&gt;The pattern usually goes something like this:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;It’s something simple. I’ll fix it in a couple of minutes and document it for others. I know my stuff. &lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Hmm, this seems to be a bit stubborn. I need to take a closer look.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Still doesn’t work. I need to run this in a debugging set up and break it into pieces, to see where the problem is. &lt;/p&gt;</description>
			</item>
			<item>
				<title>Fixing vagrant-vbguest for the centos/7 base box</title>
				<link>https://www.puppeteers.net/blog/fixing-vagrant-vbguest-for-the-centos-7-base-box/</link>
				<pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fixing-vagrant-vbguest-for-the-centos-7-base-box/</guid>
				<description>&lt;p&gt;We&amp;rsquo;re using the centos/7 base box in Vagrant a lot and often hit this problem when bringing up new VMs with Vagrant:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;umount: /mnt: not mounted&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;This error comes from vagrant-vbguest plugin which tried to install the Virtualbox Guest Additions but failed. The error message is misleading, because the real issue is related to upstream (CentOS) yum repositories. As explained in this &lt;a href=&#34;https://github.com/hashicorp/vagrant/issues/12095&#34;&gt;Vagrant bug report&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&amp;ldquo;Basically the CentOS that you&amp;rsquo;re installing is containing an old kernel version which has been removed from CentOS repositories. Vagrant is trying to install Guest Additions, which has as a dependency the kernel-devel package. kernel-devel package must be the same version as the kernel package that you have it installed in your CentOS box, version which is removed from the CentOS repos.&amp;rdquo;&lt;/em&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>Creating PXE bootable Virtualbox VMs</title>
				<link>https://www.puppeteers.net/blog/creating-pxe-bootable-virtualbox-vms/</link>
				<pubDate>Wed, 24 Feb 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/creating-pxe-bootable-virtualbox-vms/</guid>
				<description>&lt;p&gt;We use &lt;a href=&#34;https://www.vagrantup.com/&#34;&gt;Vagrant&lt;/a&gt; and &lt;a href=&#34;https://www.virtualbox.org/&#34;&gt;Virtualbox&lt;/a&gt; heavily when developing Puppet code. We also do provisioning of baremetal servers with &lt;a href=&#34;https://theforeman.org/&#34;&gt;Foreman&lt;/a&gt;. While Vagrant is a really powerful tool, it is not designed for creating VMs that boot from the network (&lt;a href=&#34;https://en.wikipedia.org/wiki/Preboot_Execution_Environment&#34;&gt;PXE boot&lt;/a&gt;). Fortunately Virtualbox itself provides a rich command-line with which you can create and configure virtual machines and configure them to boot from the network. It is assumed below that there is a PXE boot server (e.g. Foreman) created into a hostonly network with Vagrant. Here&amp;rsquo;s an example script that create a VM with vboxmanage and adds it the same hostonly network interface (vboxnet15) as the PXE boot server:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Configuring ejabberd multi-user chatrooms</title>
				<link>https://www.puppeteers.net/blog/configuring-ejabberd-multi-user-chatrooms/</link>
				<pubDate>Fri, 12 Feb 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/configuring-ejabberd-multi-user-chatrooms/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.ejabberd.im/&#34;&gt;Ejabberd&lt;/a&gt; is a very flexible and scalable XMPP server. We use it because it can be configured using a simple yaml configuration file and managed via &lt;em&gt;ejabberdctl&lt;/em&gt; commands. This makes it a good fit for our infrastructure as code approach. That said, ejabberd does require one to understand the XMPP protocol/jargon as it does not abstract away any of it. So simple things like creating chatrooms, limiting access to them and playing history backlog to users who connected them can be an effort if you&amp;rsquo;ve never done it.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ejabberd message archiving and history playback</title>
				<link>https://www.puppeteers.net/blog/ejabberd-message-archiving-and-history-playback/</link>
				<pubDate>Fri, 12 Feb 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/ejabberd-message-archiving-and-history-playback/</guid>
				<description>&lt;p&gt;When using &lt;a href=&#34;https://www.ejabberd.im/&#34;&gt;ejabberd&lt;/a&gt; in a company for multi-user chat (see &lt;a href=&#34;https://www.puppeteers.net/blog/configuring-ejabberd-multi-user-chatrooms/&#34;&gt;my earlier blog post&lt;/a&gt;) people will quickly start complaining that they missed discussions because they had been offline. Ejabberd &lt;em&gt;does&lt;/em&gt; play back last 20 messages when user joins a room, but that is too little for an active chatroom. The simplistic approach is to set &lt;em&gt;history_size&lt;/em&gt; in &lt;a href=&#34;https://docs.ejabberd.im/archive/20_04/modules/#mod-muc&#34;&gt;mod_muc settings&lt;/a&gt; in ejabberd.yml to a higher value:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;mod_muc:&#xA;  history_size: 200&#xA;  --- snip ---&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;This simplistic approach should work with any XMPP clients.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform resources with dynamic provider values</title>
				<link>https://www.puppeteers.net/blog/terraform-resources-with-dynamic-provider-values/</link>
				<pubDate>Thu, 11 Feb 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-resources-with-dynamic-provider-values/</guid>
				<description>&lt;p&gt;Sometimes you&amp;rsquo;d like to pass a dynamic value to a Terraform resource&amp;rsquo;s provider parameter. This can be done, but some background first.&lt;/p&gt;&#xA;&lt;p&gt;Terraform allows you to &lt;a href=&#34;https://www.terraform.io/docs/language/meta-arguments/resource-provider.html&#34;&gt;define multiple providers of the same type&lt;/a&gt; using provider &lt;em&gt;aliases&lt;/em&gt;. This is useful when you&amp;rsquo;re working with a provider that is tied to a region, the AWS provider being a prime example. The moment you want to create resources in multiple regions you will have to learn provider aliases.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Getting the last inactive vboxnet interface with Ruby</title>
				<link>https://www.puppeteers.net/blog/getting-the-last-inactive-vboxnet-interface-with-ruby/</link>
				<pubDate>Sat, 30 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/getting-the-last-inactive-vboxnet-interface-with-ruby/</guid>
				<description>&lt;p&gt;This could possibly be the most esoteric blog post I&amp;rsquo;ve ever written, but here it goes. So, for reasons even we have difficulty comprehending (hint: related to PXE booting in a Vagrant/Virtualbox environment) we had to find out which &lt;em&gt;inactive&lt;/em&gt; vboxnet (hostonly) interface had the highest index. We wanted the code to (hopefully) run on all platforms (Linux, MacOS, Windows) so we wanted to write this code in Ruby. So, this was the brutal but working end-result:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Authenticate and authorize Grafana users from FreeIPA groups via Keycloak</title>
				<link>https://www.puppeteers.net/blog/authenticating-and-authorizing-users-from-freeipa-groups-via-keycloak/</link>
				<pubDate>Thu, 28 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/authenticating-and-authorizing-users-from-freeipa-groups-via-keycloak/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://grafana.com&#34;&gt;Grafana&lt;/a&gt; is a common tool to visualize data from multiple datasources. Perhaps the most common datasource is &lt;a href=&#34;https://prometheus.io/docs/introduction/overview/&#34;&gt;Prometheus&lt;/a&gt;. If an organization has a Single-Sign On solution, it makes sense to authenticate users centrally with that solution That will make authentication easier and friendlier for end users (authenticate once and then access multiple services), and also enable stronger authentication by adding &lt;a href=&#34;https://en.wikipedia.org/wiki/Multi-factor_authentication&#34;&gt;multifactor authentication&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In addition to authenticating user, it is also possible to authorize Grafana users based on their group membership. &lt;/p&gt;</description>
			</item>
			<item>
				<title>Making sense of JBOSS/Wildfly interfaces in domain mode</title>
				<link>https://www.puppeteers.net/blog/making-sense-of-jboss-wildfly-interfaces-in-domain-mode/</link>
				<pubDate>Thu, 28 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-sense-of-jboss-wildfly-interfaces-in-domain-mode/</guid>
				<description>&lt;p&gt;In this blog we consider &lt;a href=&#34;https://www.jboss.org/&#34;&gt;JBoss/Wildfly&lt;/a&gt; domain mode in the context of the wonderful &lt;a href=&#34;https://www.keycloak.org/&#34;&gt;Keycloak&lt;/a&gt; software. It is not necessarily trivial to understand how the interfaces  should be configured, especially if you want to do something other than the defaults, for example to secure your Wildfly/JBOSS configuration, or if you are dealing with a more complex nodes with multiple network interfaces. &lt;/p&gt;&#xA;&lt;p&gt;Assumptions:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;We want to use Keycloak in domain mode. In this operating mode Keycloak application is clustered and also the caches, like user sessions are replicated in the cluster. &lt;/p&gt;</description>
			</item>
			<item>
				<title>Limiting the scope of puppet-rspec tests</title>
				<link>https://www.puppeteers.net/blog/limiting-the-scope-of-puppet-rspec-tests/</link>
				<pubDate>Fri, 22 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/limiting-the-scope-of-puppet-rspec-tests/</guid>
				<description>&lt;p&gt;Some Puppet modules like &lt;a href=&#34;https://github.com/treydock/puppet-module-keycloak/&#34;&gt;puppet-module-keycloak&lt;/a&gt; have hundreds of unit tests. That is good for test coverage, but waiting for test results hurts your productivity when you&amp;rsquo;re developing tests for your new code. There are at least two ways to (temporarily) limit the scope of the tests that you run. First method is baked in into the &lt;a href=&#34;https://puppet.com/try-puppet/puppet-development-kit/&#34;&gt;Puppet Development Kit&lt;/a&gt; command-line:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ pdk test unit --tests=spec/classes/init_spec.rb&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;This runs only the tests in the specified file.&lt;/p&gt;</description>
			</item>
			<item>
				<title>RIP: Puppeteers Finnish website</title>
				<link>https://www.puppeteers.net/blog/rip-puppeteers-finnish-website/</link>
				<pubDate>Mon, 18 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/rip-puppeteers-finnish-website/</guid>
				<description>&lt;p&gt;Today was a special day. Our Finnish website went to greener pastures after having spent its golden months serving permanent HTTP redirects to our current website while having been taken our of our Terraform codebase. It is customary to speak a few words in occasions like this, so here we go.&lt;/p&gt;&#xA;&lt;p&gt;&amp;ldquo;Beloved &lt;a href=&#34;https://www.puppeteers.fi&#34;&gt;www.puppeteers.fi&lt;/a&gt;. You were a well-liked website that brought us our first customer. Occasionally you were down because MySQL innodb_buffer_pool_size was set too low. Or because overall system memory went too low and the OOM killer broke you. But we cannot blame you for that - it was just us trying to spare some €€€ that caused all that. You served us well, but it was time to finally move on.&amp;rdquo;&lt;/p&gt;</description>
			</item>
			<item>
				<title>AWS to Azure resource translation table</title>
				<link>https://www.puppeteers.net/blog/aws-to-azure-resource-translation-table/</link>
				<pubDate>Sun, 17 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/aws-to-azure-resource-translation-table/</guid>
				<description>&lt;p&gt;We use Terraform for managing our Cloud infrastructure. Our customers typically use AWS and that&amp;rsquo;s what we&amp;rsquo;re most familiar with. Each public Cloud has its own terminology, so this page is a translation table between Terraform resource names in the AWS and Azure providers:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;AWS&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;&lt;strong&gt;Azure&lt;/strong&gt;&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;aws_instance&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_linux_virtual_machine&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;aws_network_interface&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_network_interface&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;aws_security_group&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_network_security_group&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;aws_security_group_rule&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_network_security_rule&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;aws_vpc&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_virtual_network&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;aws_subnet&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_subnet&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;inapplicable&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_resource_group&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;aws_s3_bucket&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;azurerm_storage_account&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;region&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;location&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Mapping of Terraform AWS resource names to Azure resource names&lt;/p&gt;</description>
			</item>
			<item>
				<title>High-level and low-level tasks in Kanban</title>
				<link>https://www.puppeteers.net/blog/high-level-and-low-level-tasks-in-kanban/</link>
				<pubDate>Sun, 17 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/high-level-and-low-level-tasks-in-kanban/</guid>
				<description>&lt;p&gt;We use Kanban to coordinate our projects and tasks. Kanban is focused on visualizing and improving throughput, that is, making projects (high-level) and tasks (low-level) go through the system as fast as by limiting work in progress, which in turn minimizes waste (time and money).&lt;/p&gt;&#xA;&lt;p&gt;Our field of work is IT operations and we&amp;rsquo;re generally quite busy with fulfilling requests from our internal and external stakeholders. Most of our tasks are quite small, about 1-4 hours each, and produce value immediately. We can generally get these done (&amp;ldquo;through the system&amp;rdquo;) quickly without having to stop in the middle and can then forget about them. However, we also have bigger tasks that tend to take a lot longer, maybe 8-24 hours of focused work and often involve multiple persons.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Querying DNS in Puppet code</title>
				<link>https://www.puppeteers.net/blog/querying-dns-in-puppet-code/</link>
				<pubDate>Wed, 06 Jan 2021 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/querying-dns-in-puppet-code/</guid>
				<description>&lt;p&gt;I recently had to add access control rules to OpenVPN Access Server to permit certain groups to access certain IP addresses. As we manage our Access Server configurations with Puppet using &lt;a href=&#34;https://github.com/OpenVPN/puppet-openvpnas&#34;&gt;puppet-openvpnas&lt;/a&gt; (by the author), we needed a way to parameterize the allowed IP addresses while keeping the Puppet code readable.&lt;/p&gt;&#xA;&lt;p&gt;This is where &lt;a href=&#34;https://forge.puppet.com/modules/dalen/dnsquery&#34;&gt;puppet-dnsquery&lt;/a&gt; came really handy. It allows using data that&amp;rsquo;s already available in DNS and using it in Puppet code. A simplistic example:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Migrating from Puppet 5 to 6 with Puppet Bolt</title>
				<link>https://www.puppeteers.net/blog/migrating-from-puppet-5-to-6-with-puppet-bolt/</link>
				<pubDate>Thu, 31 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/migrating-from-puppet-5-to-6-with-puppet-bolt/</guid>
				<description>&lt;p&gt;The main annoyance with agent-based configuration management is the management of the agents themselves. They usually don&amp;rsquo;t require any handholding after the initial install, &lt;em&gt;except&lt;/em&gt; when you need to migrate them to a new environment. For example, migrate from a Puppet 5-based server to Puppet 6.&lt;/p&gt;&#xA;&lt;p&gt;The migration process is not overly difficult, but in order to scale to more than a handful of nodes you will need to orchestrate the process. Historically we would have used Ansible for this task, but nowadays we prefer Puppet Bolt, which is more powerful and flexible in our use-cases. The Bolt plans typically end up being ugly, but based on my experience with Ansible Playbooks that tends to be the case anyways. I guess this is the natural result of mixing state-based configuration management, ad hoc commands and orchestration together.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Sed spell to ease moving to Terraform 0.13</title>
				<link>https://www.puppeteers.net/blog/sed-spell-to-ease-moving-to-terraform-0-13/</link>
				<pubDate>Mon, 28 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/sed-spell-to-ease-moving-to-terraform-0-13/</guid>
				<description>&lt;p&gt;When moving from older versions of Terraform 0.12.x to latest 0.12.x (now: 0.12.29) you may notice the following warnings:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Warning: Interpolation-only expressions are deprecated                                                                                                                              &#xA;&#xA;  on backup.tf line 11, in resource &amp;#34;hcloud_server_network&amp;#34; &amp;#34;backup_example_org&amp;#34;:                                                                                                 &#xA;  11:   server_id = &amp;#34;${module.backup_example_org.id}&amp;#34;        &lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;These make sense, but may come as a surprise as earlier 0.12.x versions were perfectly fine with them.&lt;/p&gt;&#xA;&lt;p&gt;You may have tons of these, so fixing them manually gets tiresome. The fix is not too difficult, but is quite unreadable due to escaping:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Creating custom facts programmatically</title>
				<link>https://www.puppeteers.net/blog/creating-custom-facts-programmatically/</link>
				<pubDate>Fri, 18 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/creating-custom-facts-programmatically/</guid>
				<description>&lt;p&gt;Writing static facts is fairly easy even with a low level of Ruby skills. Below is an example of a fact that returns true or false depending on whether the node has a /boot partition:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Facter.add(:has_bootfs) do&#xA;  setcode do&#xA;    if Facter.value(:mountpoints)[&amp;#39;/boot&amp;#39;].nil?&#xA;      false&#xA;    else&#xA;      true&#xA;    end&#xA;  end&#xA;end&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;As you can see above the required information was already inside the &amp;ldquo;mountpoints&amp;rdquo; fact of Facter.&lt;/p&gt;&#xA;&lt;p&gt;Using the fact is easy:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Keycloak, Wildfly and Infinispan caches</title>
				<link>https://www.puppeteers.net/blog/keycloak-wildfly-and-infinispan-caches/</link>
				<pubDate>Wed, 16 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/keycloak-wildfly-and-infinispan-caches/</guid>
				<description>&lt;p&gt;We recently hit an interesting issue with an &amp;ldquo;almost in production&amp;rdquo; Keycloak high-availability &lt;a href=&#34;https://www.keycloak.org/docs/latest/server_installation/index.html#_domain-mode&#34;&gt;clustered domain mode setup&lt;/a&gt; that was behind an Amazon EC2 load balancer with sticky sessions enabled. The symptom was that changes from the domain controller did not propagate to the slave. This included:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Changes made to realms and clients using the &lt;a href=&#34;https://www.keycloak.org/docs-api/11.0/rest-api/index.html&#34;&gt;Admin REST API&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;User sessions&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;This lead us into a quest to truly understand how &lt;a href=&#34;https://infinispan.org/&#34;&gt;Infinispan&lt;/a&gt; caches in the &lt;a href=&#34;https://www.wildfly.org/&#34;&gt;Wildfly application server&lt;/a&gt; and consequently in &lt;a href=&#34;https://www.keycloak.org/&#34;&gt;Keycloak&lt;/a&gt; work. Before you read this article you should probably read all of these:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Automatic publishing to LinkedIn now in operation</title>
				<link>https://www.puppeteers.net/blog/automatic-publishing-to-linkedin-now-in-operation/</link>
				<pubDate>Sat, 12 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/automatic-publishing-to-linkedin-now-in-operation/</guid>
				<description>&lt;p&gt;Our company is about infrastructure automation and products built on top of it. That means we really don&amp;rsquo;t want to do manually what a computer can do. Therefore it was not an option to publish our blog posts first in Wordpress, then copy-and-paste them to LinkedIn. Rather, let a Wordpress plugin configured as a LinkedIn app do the hard word. So, from now on all of our blog posts should get published automatically on our &amp;ldquo;Puppeteers Oy&amp;rdquo; LinkedIn page. Let&amp;rsquo;s hope that the automation does not break too often :).&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using the Pomodoro technique to control distractions</title>
				<link>https://www.puppeteers.net/blog/using-of-the-pomodoro-technique-to-control-distractions/</link>
				<pubDate>Sat, 12 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-of-the-pomodoro-technique-to-control-distractions/</guid>
				<description>&lt;p&gt;We - like many others - have the problem that our work gets easily interrupted. Some interruptions come from the inside. For example, you remember &amp;ldquo;a thing you need to do&amp;rdquo; and without thinking start doing it immediately. Other interruptions are external, for example a colleague ask you for advise or a customer calls you asking for help. Almost always these things &lt;em&gt;could&lt;/em&gt; wait a bit, but the person simply acted on an impulse.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Managing Keycloak configuration programmatically</title>
				<link>https://www.puppeteers.net/blog/managing-keycloak-configuration-programmatically/</link>
				<pubDate>Fri, 11 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/managing-keycloak-configuration-programmatically/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.keycloak.org/&#34;&gt;Keycloak&lt;/a&gt; is an excellent Open Source Identity and Access Management solution that builds on top of the &lt;a href=&#34;https://www.wildfly.org/&#34;&gt;Wildfly application server&lt;/a&gt;. We manage several Keycloak installations for providing SSO with FreeIPA credentials for self-hosted and SaaS services via SAML and OIDC.&lt;/p&gt;&#xA;&lt;p&gt;To keep our Keycloak configurations healthy and in a known-good state we manage their configurations programmatically. As we use Puppet for our configuration management needs we&amp;rsquo;ve contributed a lot to the &lt;a href=&#34;https://github.com/treydock/puppet-module-keycloak/&#34;&gt;treydock/puppet-module-keycloak&lt;/a&gt; project. There is also a &lt;a href=&#34;https://github.com/mrparkers/terraform-provider-keycloak&#34;&gt;Terraform Keycloak provider&lt;/a&gt; that covers the Keycloak API very well, but it won&amp;rsquo;t help you one bit with setting up Keycloak initially. This can be problematic if you&amp;rsquo;re setting up something more complex like clustered domain mode with TLS reverse proxies.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Making Prometheus and Alertmanager work behind a reverse proxy</title>
				<link>https://www.puppeteers.net/blog/making-prometheus-and-alertmanager-work-behind-a-reverse-proxy/</link>
				<pubDate>Wed, 09 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-prometheus-and-alertmanager-work-behind-a-reverse-proxy/</guid>
				<description>&lt;p&gt;We maintain a &lt;a href=&#34;https://prometheus.io/docs/introduction/overview/&#34;&gt;Prometheus&lt;/a&gt; and &lt;a href=&#34;https://prometheus.io/docs/alerting/latest/alertmanager/&#34;&gt;Alertmanager&lt;/a&gt; setup where both services are running on the same host and an Apache reverse proxy handles TLS and authentication, authorization and single sign-on with Apache &lt;a href=&#34;https://github.com/latchset/mod_auth_mellon&#34;&gt;mod_auth_mellon&lt;/a&gt; configured as a &lt;a href=&#34;https://www.keycloak.org/&#34;&gt;Keycloak&lt;/a&gt; SAML client. This way we can limit access to Prometheus and Alertmanager to people who belong to a certain &lt;a href=&#34;https://www.freeipa.org/page/Main_Page&#34;&gt;FreeIPA&lt;/a&gt; group.&lt;/p&gt;&#xA;&lt;p&gt;From end-user perspective Prometheus and Alertmanager are available at these locations:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://prometheus.example.org/prometheus&#34;&gt;https://prometheus.example.org/prometheus&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://prometheus.example.org/alertmanager&#34;&gt;https://prometheus.example.org/alertmanager&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In this setup both Prometheus and Alertmanager require additional startup options to work correctly. First Prometheus:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Fattening the workflow, part 5: Hiera and content encryption</title>
				<link>https://www.puppeteers.net/blog/fattening-the-workflow-part-5-hiera-and-content-encryption/</link>
				<pubDate>Thu, 03 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fattening-the-workflow-part-5-hiera-and-content-encryption/</guid>
				<description>&lt;p&gt;Separating data from code in Puppet modules is advisable as it improves reusability of code. The separation can be accomplished with Hiera by having separate levels based on facts, organizational units, locations, etc.&lt;/p&gt;&#xA;&lt;p&gt;Hiera can also be used for storing private data that needs to be protected and must not be readable by outsiders. Typically the data, like all other code, is stored in a version control system that may be located outside the organisation. In such a case Hiera encryption is a must.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Fattening the workflow, part 4: Roles and profiles</title>
				<link>https://www.puppeteers.net/blog/fattening-the-workflow-part-4-roles-and-profiles/</link>
				<pubDate>Wed, 02 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fattening-the-workflow-part-4-roles-and-profiles/</guid>
				<description>&lt;p&gt;If the workflow that includes the &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-puppet-workflow-part-1-the-control-repository/&#34;&gt;control repository&lt;/a&gt;, &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-workflow-part-2-r10k/&#34;&gt;r10k&lt;/a&gt; and &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-workflow-part-3-gitlab-and-similar/&#34;&gt;GitLab&lt;/a&gt; still feels too light, there are yet more ways to make the workflow heavier by adding more abstraction to the Puppet modules themselves. This is done by adopting the &amp;ldquo;Roles and Profiles pattern&amp;rdquo; that was &lt;a href=&#34;http://craigdunn.org/2012/05/239/&#34;&gt;developed by Craig Dunn&lt;/a&gt; and popularized in the blog posts by &lt;a href=&#34;http://garylarizza.com/&#34;&gt;Gary Larizza&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Roles and profiles are just Puppet classes. Profiles are usually used for creating technology stacks. A good example is a web application whose installation requires a web server (nginx, apache), a database server (postgresql, mysql) and several other components. The configurations for such an application could of course be done with a &amp;ldquo;regular&amp;rdquo; Puppet module but the reusability of the module would be rather limited for two reasons:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Fattening the workflow, part 2: r10k</title>
				<link>https://www.puppeteers.net/blog/fattening-the-workflow-part-2-r10k/</link>
				<pubDate>Tue, 01 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fattening-the-workflow-part-2-r10k/</guid>
				<description>&lt;p&gt;In the previous post I discussed the &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-puppet-workflow-part-1-the-control-repository/&#34;&gt;control repository structure&lt;/a&gt;. In this post I&amp;rsquo;ll talk about &lt;a href=&#34;https://github.com/puppetlabs/r10k&#34;&gt;r10k&lt;/a&gt;. That tool is used for deploying control repository branches into matching Puppet environments on the Puppet server. Installing r10k is very straightforward with the bundled gem:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ /opt/puppetlabs/puppet/bin/gem install r10k&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;After this you&amp;rsquo;ll need a settings file for r10k, &lt;em&gt;/etc/puppetlabs/r10k/r10k.yaml:&lt;/em&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;--- &#xA; :cachedir: /opt/puppetlabs/puppet/cache/r10k &#xA; :sources: &#xA; control: &#xA; basedir: /etc/puppetlabs/code/environments &#xA; prefix: false &#xA; remote: git@gitlab.com:myorg/control-repo.git&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Several requirements must be met before the configuration above will work:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Fattening the workflow, part 3: GitLab and similar</title>
				<link>https://www.puppeteers.net/blog/fattening-the-workflow-part-3-gitlab-and-similar/</link>
				<pubDate>Tue, 01 Dec 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fattening-the-workflow-part-3-gitlab-and-similar/</guid>
				<description>&lt;p&gt;In the previous posts of this series I discussed &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-puppet-workflow-part-1-the-control-repository/&#34;&gt;the control repository&lt;/a&gt; and &lt;a href=&#34;https://www.puppeteers.net/blog/fattening-the-workflow-part-2-r10k/&#34;&gt;r10k&lt;/a&gt;. The last component in fattening the workflow is Git provider such as GitLab, GitHub or Bitbucket. Nowadays all of them are reasonable choices for storing private Git modules, which Puppet control repositories and site-specific modules tend to be. One of the biggest advantages of GitLab over its competition is that it is open source and can be installed locally.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Fattening the Puppet workflow, part 1: The control repository</title>
				<link>https://www.puppeteers.net/blog/fattening-the-puppet-workflow-part-1-the-control-repository/</link>
				<pubDate>Thu, 26 Nov 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/fattening-the-puppet-workflow-part-1-the-control-repository/</guid>
				<description>&lt;p&gt;If editing Puppet code and Hiera directly with puppetmaster feels too easy, you can complicate the Puppet workflow as much you like by adding more components to the palette. Adding the so called &lt;a href=&#34;https://puppet.com/docs/pe/2017.3/code_management/control_repo.html&#34;&gt;control repository&lt;/a&gt; and &lt;a href=&#34;https://puppet.com/docs/puppet/5.3/environments_about.html&#34;&gt;r10k&lt;/a&gt; to Puppet environment maintenance instantly adds several phases to your initially simple workflow. There are also benefits that I&amp;rsquo;ll discuss later on.&lt;/p&gt;&#xA;&lt;p&gt;The control repository (control repo for short) is a Git repository that is used to create dynamic Puppet environments on the Puppet master. Each Git branch can be turned into a matching Puppet environment. The name of the default branch, production, is the same as the environment the Puppet agents use by default. The content of the control repo branches look like this:&lt;/p&gt;</description>
			</item>
			<item>
				<title>SEM tips: how to get started easily</title>
				<link>https://www.puppeteers.net/blog/sem-tips-how-to-get-started-easily/</link>
				<pubDate>Fri, 20 Nov 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/sem-tips-how-to-get-started-easily/</guid>
				<description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;The purpose of this post is to show that search engine marketing (SEM) can be started rather easily. Small businesses, like our company, may not have resources (money, knowledge, time etc) to spend on marketing and consultancy so I&amp;rsquo;m hoping that sharing this experience will help and encourage other SEM newbies!&lt;/p&gt;&#xA;&lt;p&gt;This blog post is in no means a complete SEM tutorial. There are plenty online, paid and free (I&amp;rsquo;ll list some in the next chapter). My idea instead is to focus on the main points for getting started with SEM and also to enlighten some of they key concepts and terms. I&amp;rsquo;m trying to write down things that I hope I had heard of before starting with SEM!&lt;/p&gt;</description>
			</item>
			<item>
				<title>Making per-link DNS servers pushed from OpenVPN to systemd-resolved survive NetworkManager connection changes</title>
				<link>https://www.puppeteers.net/blog/making-per-link-dns-servers-pushed-from-openvpn-to-systemd-resolved-survive-networkmanager-connection-changes/</link>
				<pubDate>Tue, 03 Nov 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/making-per-link-dns-servers-pushed-from-openvpn-to-systemd-resolved-survive-networkmanager-connection-changes/</guid>
				<description>&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; the problem described in this article seems to be resolved in Fedora 36 (NetworkManager 1.38.0-2.fc36). It is still present in Fedora 35 (NetworkManager 1.32.12-2.fc35).&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; there a companion article about solving this problem for Wireguard in &lt;a href=&#34;https://www.puppeteers.net/blog/making-per-link-dns-servers-added-by-wireguard-to-systemd-resolved-survive-networkmanager-connection-changes/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;In an the &lt;a href=&#34;https://www.puppeteers.net/blog/manage-linux-client-dns-settings-in-openvpn-and-wireguard/&#34;&gt;Manage Linux client DNS settings in OpenVPN and Wireguard&lt;/a&gt; article we described how to use the &lt;a href=&#34;https://github.com/jonathanio/update-systemd-resolved&#34;&gt;update-systemd-resolved&lt;/a&gt; script to update systemd-resolved per-link DNS servers automatically based on DNS servers pushed from an OpenVPN server. This is very convenient if you have to be connected to multiple remote locations each with their own DNS servers and zones.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform 0.11-&gt;0.12 migration: stabs at the state file</title>
				<link>https://www.puppeteers.net/blog/terraform-0-11-0-12-migration-stabs-at-the-state-file/</link>
				<pubDate>Fri, 30 Oct 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-0-11-0-12-migration-stabs-at-the-state-file/</guid>
				<description>&lt;p&gt;We maintain a rather complex AWS environment built with Terraform that uses nested modules and lots of per-resource provider configurations. Recently the pain of staying with Terraform 0.11 became too much, so we had to start the migration to Terraform 0.12, with 0.13 going to follow soon after. In general the &lt;a href=&#34;https://www.terraform.io/upgrade-guides/0-12.html&#34;&gt;official upgrade instructions&lt;/a&gt; were pretty good. Of course there was a lot of manual fixing that had to be done, and as I did not keep detailed notes I can&amp;rsquo;t recall all the steps I went through. But I think all or most of those can be found from other sources.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using Puppet Bolt to apply roles to nodes, part 1</title>
				<link>https://www.puppeteers.net/blog/using-puppet-bolt-to-apply-roles-to-nodes-part-1/</link>
				<pubDate>Sat, 17 Oct 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-puppet-bolt-to-apply-roles-to-nodes-part-1/</guid>
				<description>&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; this article is somewhat outdated. Please refer to &lt;a href=&#34;https://www.puppeteers.net/blog/serverless-puppet-with-control-repo-hiera-roles-and-profiles-and-puppet-bolt/&#34;&gt;Serverless Puppet with control repo, Hiera, roles and profiles and Puppet Bolt&lt;/a&gt; instead.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://puppet.com/docs/bolt/latest/bolt.html&#34;&gt;Puppet Bolt&lt;/a&gt; is a designed to be an orchestration tool, but it can be used for configuration management as well. For example you may have a small environment of handful of nodes where having a dedicated Puppet server would be an overkill, or you have some nodes in the infrastructure where you can&amp;rsquo;t or don&amp;rsquo;t want to install a Puppet Agent.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Improving Vim&#39;s Puppet integration</title>
				<link>https://www.puppeteers.net/blog/improving-vims-puppet-integration/</link>
				<pubDate>Thu, 15 Oct 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/improving-vims-puppet-integration/</guid>
				<description>&lt;p&gt;A recent package upgrade seemed to break Puppet syntax highlighting horribly on my Fedora 32 laptop. Not only did syntax highlighting not work, it was actually completely wrong and confusing. It seemed as if the Puppet file type detection was missing, so vim was probably using some a syntax highlighter for a wrong type. To see which file types are enabled I used &lt;code&gt;:set filetype&lt;/code&gt; followed by a couple of tabs (more details on &lt;a href=&#34;https://vi.stackexchange.com/questions/5780/list-known-filetypes&#34;&gt;StackExchange&lt;/a&gt;).&lt;/p&gt;</description>
			</item>
			<item>
				<title>LibreNMS image 1.65-20 released</title>
				<link>https://www.puppeteers.net/blog/librenms-image-1-65-20-released/</link>
				<pubDate>Tue, 22 Sep 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/librenms-image-1-65-20-released/</guid>
				<description>&lt;p&gt;&lt;img src=&#34;https://puppeteers-public.hel1.your-objectstorage.com/LibreNMS-logo.png&#34; alt=&#34;&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.net/products/librenms-image/&#34;&gt;LibreNMS image&lt;/a&gt; version 1.65-20 &lt;a href=&#34;https://aws.amazon.com/marketplace/pp/B08FMQTC98?&#34;&gt;is now available&lt;/a&gt; in the AWS Marketplace. It is a a Cloud image that runs a pre-configured &lt;a href=&#34;https://www.librenms.org/&#34;&gt;LibreNMS network monitoring system&lt;/a&gt;. It is the easiest and fastest way to get started with LibreNMS.&lt;/p&gt;&#xA;&lt;p&gt;Pricing is based on usage: there are no up-front license fees or other costs. This means you can test it with zero risk. Also, there is currently a &lt;strong&gt;free trial&lt;/strong&gt;!&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://aws.amazon.com/marketplace/pp/B08FMQTC98?&#34;&gt;Purchase now in AWS Marketplace!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
			</item>
			<item>
				<title>I search</title>
				<link>https://www.puppeteers.net/blog/i-search/</link>
				<pubDate>Fri, 04 Sep 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/i-search/</guid>
				<description>&lt;p&gt;The keys on your laptop are the kind of item you don&amp;rsquo;t pay any attention until you lose them. The &amp;ldquo;O&amp;rdquo; key came off from my Carbon X1 keyboard a few days ago. I was able to postpone the ultimate solution by a couple of days by just pushing the &amp;ldquo;O&amp;rdquo; back. But doing that five times a day got old soon. So, I took of another key - &amp;ldquo;I&amp;rdquo; - to figure out the correct alignment for the metal hooks that hold the plastic hinges in place. That was a good idea &lt;em&gt;on paper&lt;/em&gt; except that I was able to break the hinge when installing the &amp;ldquo;I&amp;rdquo; back. After a failed attempt of gluing the hinge together with a generous amount of epoxy I gave up and decided to order replacement keys.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Restrict access to a location in Apache reverse proxy with TLS</title>
				<link>https://www.puppeteers.net/blog/restrict-access-to-a-location-in-apache-reverse-proxy-with-tls/</link>
				<pubDate>Fri, 04 Sep 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/restrict-access-to-a-location-in-apache-reverse-proxy-with-tls/</guid>
				<description>&lt;p&gt;Ever had a case where you needed to use a name based Apache reverse proxy in front of some application server, while restring access to some proxied location at the same time? Here’s how to do it.&lt;/p&gt;&#xA;&lt;h3 id=&#34;first-define-a-virtual-host&#34;&gt;First define a virtual host:&lt;/h3&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;VirtualHost *:443&amp;gt;&#xA;    ServerName myserver.example.com&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;h3 id=&#34;set-the-request-headers-you-are-of-course-using-tls-arent-you&#34;&gt;Set the request headers (you are of course using TLS, aren&amp;rsquo;t you):&lt;/h3&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;RequestHeader set X-Forwarded-Proto &amp;#34;https&amp;#34;&#xA;RequestHeader set X-Forwarded-Port &amp;#34;443&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;h3 id=&#34;proxy-to-some-internal-address-here-to-localhost-port-8080&#34;&gt;Proxy to some internal address, here to localhost port 8080:&lt;/h3&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ProxyRequests Off&#xA;ProxyPreserveHost On&#xA;ProxyPass http://127.0.0.1:8080/&#xA;ProxyPassReverse http://127.0.0.1:8080/&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;h3 id=&#34;restrict-access-to-the-host-or-networks-you-need-to&#34;&gt;Restrict access to the host or networks you need to:&lt;/h3&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;lt;Location &amp;#34;/my/location/&amp;#34;&amp;gt;&#xA; Require ip 10.0.0.0/8&#xA;&amp;lt;/Location&amp;gt;&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Note: this will work with Apache 2.4 and up. With older versions you can use the same idea.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Debugging Packer provisioning</title>
				<link>https://www.puppeteers.net/blog/debugging-packer-provisioning/</link>
				<pubDate>Wed, 05 Aug 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/debugging-packer-provisioning/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.packer.io/&#34;&gt;Packer&lt;/a&gt; is an excellent tool for automating creation of machine images such as AWS AMIs or Docker container images. This is particularly useful when you need to scale up by spinning up instances on-demand or if you want to package software that is challenging to manage with a configuration management system. It is also extremely useful when creating actual packaged product for AWS Marketplace, for example.&lt;/p&gt;&#xA;&lt;p&gt;In Packer you take a &amp;ldquo;base box&amp;rdquo; such as Ubuntu 18.04 base image and modify its contents with provisioning, for example to install and configure software on the image. Several different types of provisioners are supported, including but not limited to shell scripts, Puppet manifests and Ansible playbooks. The concept of provisioners is the same as in &lt;a href=&#34;https://www.vagrantup.com/&#34;&gt;Vagrant&lt;/a&gt; and &lt;a href=&#34;https://www.terraform.io/&#34;&gt;Terraform&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Taming apt timers in Ubuntu 18.04</title>
				<link>https://www.puppeteers.net/blog/taming-apt-timers-in-ubuntu-18-04/</link>
				<pubDate>Wed, 05 Aug 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/taming-apt-timers-in-ubuntu-18-04/</guid>
				<description>&lt;p&gt;Ubuntu 18.04 AWS images - and probably other Cloud images as well - have automated upgrades turned on. This is done via two &lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd.timer.html&#34;&gt;systemd timers&lt;/a&gt;, &lt;em&gt;apt-daily.timer&lt;/em&gt; and &lt;em&gt;apt-daily-upgrade.timer&lt;/em&gt;. The timers kick of periodically as well as when an instance is rebooted. This sounds reasonable until you are provisioning something: you&amp;rsquo;re unable to install or configure any packages while apt and/or dpkg are running. With a really fresh cloud base image this &lt;em&gt;may&lt;/em&gt; not be an issue, but when the base image gets sufficiently old then &lt;em&gt;apt-get upgrade&lt;/em&gt; starts taking enough time to cause issues.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Nagios-plugin-cloudwatch released</title>
				<link>https://www.puppeteers.net/blog/nagios-plugin-cloudwatch-released/</link>
				<pubDate>Fri, 26 Jun 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/nagios-plugin-cloudwatch-released/</guid>
				<description>&lt;p&gt;We recently wrote a Nagios plugin for getting metrics from AWS Cloudwatch to LibreNMS. As the customer was ok with releasing it as open source &lt;a href=&#34;https://github.com/Puppet-Finland/nagios-plugin-cloudwatch&#34;&gt;here&lt;/a&gt; it is. It is written in Ruby - we like the language and we&amp;rsquo;re also Puppet guys, so it felt like a natural choice for us.&lt;/p&gt;&#xA;&lt;p&gt;The plugin allows getting as many metrics you want from Cloudwatch and setting alert thresholds (warning, critical) for each metric statistic (e.g. &lt;em&gt;&amp;ldquo;average CPUUtilization percent&amp;rdquo;&lt;/em&gt;) separately. In many cases it is not useful to configure alerts for a metric (e.g. &lt;em&gt;&amp;ldquo;minimum CPUUtilization percent&amp;rdquo;&lt;/em&gt;), but you do want to graph it regardless - this plugins allows that.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Testing connection recovery with ss</title>
				<link>https://www.puppeteers.net/blog/testing-connection-recovery-with-ss/</link>
				<pubDate>Sat, 30 May 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/testing-connection-recovery-with-ss/</guid>
				<description>&lt;p&gt;As mentioned in our &lt;a href=&#34;https://www.puppeteers.net/blog/email-to-xmpp-bridge-milter-xmpp-released/&#34;&gt;earlier blog post&lt;/a&gt; we created an &amp;ldquo;email to XMPP bridge&amp;rdquo; called &lt;a href=&#34;https://github.com/Puppet-Finland/milter-xmpp/&#34;&gt;milter-xmpp&lt;/a&gt; for forwarding alert emails from monitoring systems to an XMPP chatroom. It was known that if the connection to the XMPP server ever died the bridge would stop working, but we wanted to know how fast that would happen. It took some days, but eventually the connection died.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;a href=&#34;https://github.com/Puppet-Finland/milter-xmpp/commit/753381339cb4a750e758a33a61c0050236fc0297&#34;&gt;fix&lt;/a&gt; ended up being quite trivial, but we needed a way to break the connection. Fortunately the good folks at StackExchange already &lt;a href=&#34;https://unix.stackexchange.com/questions/71940/killing-tcp-connection-in-linux&#34;&gt;had a good solution&lt;/a&gt;: use the &amp;ldquo;ss&amp;rdquo; tool (&amp;ldquo;another utility to investigate sockets&amp;rdquo;) which provides output similar to netstat:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Email to XMPP bridge &#34;milter-xmpp&#34; released</title>
				<link>https://www.puppeteers.net/blog/email-to-xmpp-bridge-milter-xmpp-released/</link>
				<pubDate>Tue, 26 May 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/email-to-xmpp-bridge-milter-xmpp-released/</guid>
				<description>&lt;p&gt;We have used &lt;a href=&#34;https://en.wikipedia.org/wiki/XMPP&#34;&gt;XMPP&lt;/a&gt; (Jabber) for our internal discussions for years. In the recent years it &lt;em&gt;seems&lt;/em&gt; that XMPP has lost some of its traction. For example, Google and Facebook used to use XMPP for instant message and Slack used to have an XMPP bridge in their service. All of those are now gone and have been replaced with proprietary messaging protocols. In the context of a big company having all the control over the protocol probably makes sense, but it of course makes life difficult for users who have to have a separate client for each or have to use a multi-protocol client such &lt;a href=&#34;https://pidgin.im/&#34;&gt;Pidgin&lt;/a&gt; just to keep their sanity. And none of the big players seems to &amp;ldquo;winning the war&amp;rdquo; for users.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ubuntu and Debian preseeding tips</title>
				<link>https://www.puppeteers.net/blog/ubuntu-and-debian-preseeding-tips/</link>
				<pubDate>Mon, 18 May 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/ubuntu-and-debian-preseeding-tips/</guid>
				<description>&lt;p&gt;Over the years I&amp;rsquo;ve had to automate installation of Ubuntu and Debian installers a number of times. The primary motivation has always been to avoid all the questions about timezone, locale, partitioning and which packages to install &lt;em&gt;and&lt;/em&gt; to not have to babysit the installation. In theory automating the installation is as simple as writing a &lt;a href=&#34;https://wiki.debian.org/DebianInstaller/Preseed&#34;&gt;preseed file&lt;/a&gt;. In practice it is much harder for a number of reasons:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Documentation on the Internet around custom installation media and preseeding setup is anecdotal at best - it gets you going and then lets you fall on your face. The official documentation is pretty good, though.&lt;/li&gt;&#xA;&lt;li&gt;The exact format of the preseed questions varies by operating system &lt;em&gt;version&lt;/em&gt;, not just by operating system (Debian, Ubuntu).&lt;/li&gt;&#xA;&lt;li&gt;In most cases questions about locale and keyboard layout must have answers &lt;em&gt;before&lt;/em&gt; the installer preseed is even loaded. This is misleading, because the preseed file &lt;em&gt;does&lt;/em&gt; have those questions, even though the answers have zero practical effect for the installer.&lt;/li&gt;&#xA;&lt;li&gt;There are many ways to accomplish preseeding, most notably by creating a custom installation medium with the preseed file, or by getting the preseed from an URL (&amp;ldquo;auto mode&amp;rdquo;).&lt;/li&gt;&#xA;&lt;li&gt;The default keyboard layout in most Ubuntu/Debian installer is en-US. This is fine, except when you don&amp;rsquo;t have an American keyboard: then you will be struggling to find characters such as &amp;ldquo;:&amp;rdquo; or &amp;ldquo;/&amp;rdquo;, which are relatively essential when loading the preseed file from an URL.&lt;/li&gt;&#xA;&lt;li&gt;It is impossible to remember how to start &amp;ldquo;automated install&amp;rdquo; from a vanilla installer menu, let alone figure out what the keyboard and locale settings should look like on the kernel command-line.&lt;/li&gt;&#xA;&lt;li&gt;The installer is happy to produce unworking configurations (e.g. no bootloader or no kernel) without giving any hints why things are not working.&lt;/li&gt;&#xA;&lt;li&gt;Each mistake is costly in time, especially if it affects something like Grub configuration which happens at the end of the install.&lt;/li&gt;&#xA;&lt;li&gt;Because of above, you tend to try to make as many changes to the kernel command line and/or preseeding as possible in one go. This means that when you get things working you don&amp;rsquo;t know what the proper fix was, and don&amp;rsquo;t feel like repeating the process to find out.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In order not to be completely negative here is the general recipe for success:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using snmpwalk to debug SNMPv3 issues</title>
				<link>https://www.puppeteers.net/blog/using-snmpwalk-to-debug-snmpv3-issues/</link>
				<pubDate>Thu, 14 May 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-snmpwalk-to-debug-snmpv3-issues/</guid>
				<description>&lt;p&gt;Our &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-snmpd&#34;&gt;puppet-snmpd module&lt;/a&gt; support SNMPv3 very well across a wide range of operating systems. Because o that SNMPv3 is what we use across the board in multiple environments. However, in the rare cases when I have to debug SNMP problems I can never remember the exact snmpwalk command-lines to use. So, here is the usual way to run snmpwalk to figure out if SNMP is providing data:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ snmpwalk -Os -v 3 -u monitor -l authPriv -a sha -A &amp;lt;auth-pass&amp;gt; -x AES -X &amp;lt;encryption-pass&amp;gt; hostname&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Run from the monitoring server (e.g. &lt;a href=&#34;https://www.librenms.org/&#34;&gt;LibreNMS&lt;/a&gt; configured with &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-librenms/&#34;&gt;puppet-librenms&lt;/a&gt;) to make sure basic connectivity and access controls are correct as well. Or against localhost if you&amp;rsquo;re interested in the data and not connectivity.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Webinaaritallenne: Infrastruktuurin rakentaminen koodilla</title>
				<link>https://www.puppeteers.net/blog/webinaaritallenne-infrastruktuurin-rakentaminen-koodilla/</link>
				<pubDate>Wed, 06 May 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/webinaaritallenne-infrastruktuurin-rakentaminen-koodilla/</guid>
				<description>&lt;p&gt;Järjestimme &lt;a href=&#34;https://turkubusinessregion.com/&#34;&gt;Turku Business Region&lt;/a&gt;in kanssa yhteistyössä webinaarin 5.5.2020 aiheesta &amp;ldquo;Infrastruktuurin rakehtaminen koodilla&amp;rdquo;. Webinaaritallenne on saatavilla täällä:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=pfT8lU_teuM&amp;amp;t=1s&#34;&gt;Infrastruktuurin rakentaminen koodilla&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Webinaarissa käsiteltiin perusasioita seuraavista aiheista: infrastruktuurin rakentaminen koodilla eli IaC, versionhallint, laadunhallintamenetelmät sekä työkalut kuten Puppet, Terraform, Ansible sekä Puppet Bolt.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Video: infrastruktuurin rakentaminen koodilla</title>
				<link>https://www.puppeteers.net/blog/video-infrastruktuurin-rakentaminen-koodilla/</link>
				<pubDate>Tue, 05 May 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/video-infrastruktuurin-rakentaminen-koodilla/</guid>
				<description>&lt;p&gt;Tässä webinaaritallenteessa esittelemme perusteet infrastruktuurin rakentamisesta koodilla, mukaan luettuna versionhallinnan, laadunvarmistuksen ja erilaiset työkalut kuten Puppetin, Terraformin, Ansiblen ja Puppet Boltin:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=pfT8lU_teuM&amp;amp;t=1s&#34;&gt;Infrastruktuurin rakentaminen koodilla&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Toteutettu yhteistyössä &lt;a href=&#34;https://turkubusinessregion.com/&#34;&gt;Turku Business Regionin&lt;/a&gt; kanssa 5.5.2020.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet types and providers development part 3: on resource uniqueness</title>
				<link>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-3-on-resource-uniqueness/</link>
				<pubDate>Sat, 25 Apr 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-3-on-resource-uniqueness/</guid>
				<description>&lt;p&gt;This blog post is a part of this blog post series:&lt;/p&gt;&#xA;&lt;p&gt;In the previous blog post &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-2-creating-a-resource/&#34;&gt;we talked about how to create a resource, a LibreNMS service, in the provider implementation&lt;/a&gt;. This blog post will talk about &lt;em&gt;identifying&lt;/em&gt; a resource that is being managed. This is a requirement for &lt;em&gt;modifying&lt;/em&gt; existing resources.&lt;/p&gt;&#xA;&lt;p&gt;Modifying existing resources can actually be more tricky than it seems, because you first need to figure out &lt;em&gt;if&lt;/em&gt; the resource Puppet is managing already exists on the target system. In many cases the resource type you&amp;rsquo;re managing has an attribute - for example &amp;ldquo;name&amp;rdquo;, &amp;ldquo;hostname&amp;rdquo;, &amp;ldquo;fqdn&amp;rdquo;, &amp;ldquo;ip&amp;rdquo; - that is guaranteed to be unique at the target system and works well as the identifier at the Puppet end. This is the case, for example with files (fully-qualified path), packages (name of the package) and in our particular case, LibreNMS devices (&lt;a href=&#34;https://github.com/Puppet-Finland/puppet-librenms/blob/master/lib/puppet/provider/librenms_device/api.rb&#34;&gt;hostname&lt;/a&gt;).&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet types and providers development part 4: caching resource properties to improve performance</title>
				<link>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-4-caching-resource-properties-to-improve-performance/</link>
				<pubDate>Sat, 25 Apr 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-4-caching-resource-properties-to-improve-performance/</guid>
				<description>&lt;p&gt;This blog post is a part of this blog post series:&lt;/p&gt;&#xA;&lt;p&gt;In the previous blog post we talked about &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-3-on-resource-uniqueness/&#34;&gt;how to identify the resources that are being managed&lt;/a&gt;. This post will talk about the various ways of fetching the current state of the resources you wish to manage.&lt;/p&gt;&#xA;&lt;p&gt;Puppet manages a resource&amp;rsquo;s properties by checking their current state and if the current state differs from the state defined in the Puppet manifest (&amp;ldquo;desired state&amp;rdquo;) then Puppet will execute the commands necessary to fix the situation. So, when writing a Puppet provider you need to figure out a way to get the current state of all the resources of the &lt;em&gt;type&lt;/em&gt; (e.g. file, package, LibreNMS service) you&amp;rsquo;re managing as efficiently as possible.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Integrating Puppet Bolt with PuppetDB</title>
				<link>https://www.puppeteers.net/blog/integrating-puppet-bolt-with-puppetdb/</link>
				<pubDate>Fri, 24 Apr 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/integrating-puppet-bolt-with-puppetdb/</guid>
				<description>&lt;p&gt;In the &lt;a href=&#34;https://www.puppeteers.net/blog/integrating-puppet-bolt-with-puppetdb/&#34;&gt;Puppet Bolt with a Puppet control repository&lt;/a&gt; blog post we showed how to integrate Puppet Bolt with an existing control repository. We used a static inventory file, which is ok for testing or when you have a few target nodes. However, if you have a Puppetserver running and are not using Bolt to manage the &lt;em&gt;configurations&lt;/em&gt; of your nodes, then the chances are that you have a fairly large node population and maintaining a static inventory would be both tedious and error-prone. One option &lt;a href=&#34;https://puppet.com/docs/bolt/latest/using_plugins.html&#34;&gt;among many&lt;/a&gt; is to use the PuppetDB plugin to generate a dynamic inventory and that is what we describe here.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Webinaari: etäyhteydet tietoturvallisesti kuntoon VPN:llä</title>
				<link>https://www.puppeteers.net/blog/webinaari-etayhteydet-tietoturvallisesti-kuntoon-vpnlla/</link>
				<pubDate>Tue, 14 Apr 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/webinaari-etayhteydet-tietoturvallisesti-kuntoon-vpnlla/</guid>
				<description>&lt;p&gt;Turku Business Region webinaari 22.4.2020 kello 13–13.30, osana ICT-webinaarisarjaa.&lt;/p&gt;&#xA;&lt;p&gt;Webinaarinaarissa kerromme lyhyesti mitä VPN (&amp;ldquo;Virtual Private Network&amp;rdquo;) tarkoittaa ja miksi VPN:n käyttö on käytännössä välttämätöntä turvallisten etäyhteyksien luomisessa. Lisäksi käymme lyhyesti läpi VPN-yhteyksien käyttöönoton yleiset vaatimukset.&lt;/p&gt;&#xA;&lt;p&gt;Tämän jälkeen esittelemme &lt;a href=&#34;https://openvpn.net/community/&#34;&gt;OpenVPN&lt;/a&gt;:n, avoimen lähdekoodin VPN-sovelluksen, jota käytetään erittäin laajalti ympäri maailmaa. Sitten siirrymme OpenVPN:ään pohjautuvaan kaupalliseen &lt;a href=&#34;https://openvpn.net/vpn-server-resources/openvpn-access-server-features-overview/&#34;&gt;OpenVPN Access Serveriin&lt;/a&gt;, joka tekee VPN-yhteyksien luomisesta ja ylläpidosta merkittävästi helpompaa. Esittelyn jälkeen teemme OpenVPN Access Serverin käyttödemon:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet environment leakage</title>
				<link>https://www.puppeteers.net/blog/puppet-environment-leakage/</link>
				<pubDate>Wed, 01 Apr 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-environment-leakage/</guid>
				<description>&lt;p&gt;Occasionally when working with feature branch and updating types and providers you may run into &lt;a href=&#34;https://puppet.com/docs/puppet/5.5/environment_isolation.html&#34;&gt;environment leakage issues&lt;/a&gt;. They manifest themselves as issues that make no particular sense and are caused by the wrong version of a type/provider such as puppetlabs-apt (see this &lt;a href=&#34;https://tickets.puppetlabs.com/browse/MODULES-8019&#34;&gt;issue&lt;/a&gt;) leaking into your feature environment. This can happen when you update external modules in your Puppetfile. The solution (or band-aid) is fortunately fairly easy. On the Puppetmaster run this command:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Manage Linux client DNS settings in OpenVPN and Wireguard</title>
				<link>https://www.puppeteers.net/blog/manage-linux-client-dns-settings-in-openvpn-and-wireguard/</link>
				<pubDate>Tue, 31 Mar 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/manage-linux-client-dns-settings-in-openvpn-and-wireguard/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://openvpn.net/&#34;&gt;OpenVPN&lt;/a&gt; and &lt;a href=&#34;https://www.wireguard.com/&#34;&gt;Wireguard&lt;/a&gt; are both used to provide secure, remote access to an organization&amp;rsquo;s internal services such as network shares (NFS and Samba), desktops and servers (SSH and RDP) or web services. Linux is generally a first-class citizen as far as clients are concerned but with one exception: accessing DNS through the VPN tunnel.&lt;/p&gt;&#xA;&lt;p&gt;OpenVPN servers have the concept of pushing settings such as DNS servers to client. This happens by emulating a DHCP server. Windows OpenVPN clients for example are able to process this information automatically to update the (per-link) DNS server settings automatically. But Linux traditionally has not had this capability without support from &amp;ldquo;up&amp;rdquo; and &amp;ldquo;down&amp;rdquo; scripts. When one is using &lt;a href=&#34;https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html&#34;&gt;systemd-resolved&lt;/a&gt; the traditional ways such as using resolvconf or modifying /etc/resolv.conf directly no longer work or cause issues. Fortunately there is a good script, &lt;a href=&#34;https://github.com/jonathanio/update-systemd-resolved&#34;&gt;update-systemd-resolved&lt;/a&gt;, for automating the DNS server setup process for systemd-resolved. Basically it takes the list of DNS settings OpenVPN provides and converts them into dbus calls that modify the running systemd-resolved&amp;rsquo;s configuration.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet Bolt with a Puppet control repository</title>
				<link>https://www.puppeteers.net/blog/puppet-bolt-with-a-puppet-control-repository/</link>
				<pubDate>Mon, 30 Mar 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-bolt-with-a-puppet-control-repository/</guid>
				<description>&lt;p&gt;&lt;strong&gt;NOTE:&lt;/strong&gt; this article is somewhat outdated. Please refer to &lt;a href=&#34;https://www.puppeteers.net/blog/serverless-puppet-with-control-repo-hiera-roles-and-profiles-and-puppet-bolt/&#34;&gt;Serverless Puppet with control repo, Hiera, roles and profiles and Puppet Bolt&lt;/a&gt; instead.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://puppet.com/docs/bolt/latest/bolt.html&#34;&gt;Puppet Bolt&lt;/a&gt; is an orchestration tool similar to &lt;a href=&#34;https://www.ansible.com/&#34;&gt;Ansible&lt;/a&gt;. It is suitable for multiple use-cases:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Running ad hoc commands on target nodes. We use this approach for testing Puppet feature branches before approving and merging them.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;One-off configurations written in the Puppet language&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Masterless Puppet environments (look &lt;a href=&#34;https://puppet.com/blog/introducing-masterless-puppet-bolt/&#34;&gt;here&lt;/a&gt;). You may not always have enough privileges, trust or will to manage a complete Puppet infrastructure including Puppetserver, PuppetDB and Puppet Agents.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Simple orchestration with Puppet Bolt</title>
				<link>https://www.puppeteers.net/blog/simple-orchestration-with-puppet-bolt/</link>
				<pubDate>Mon, 30 Mar 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/simple-orchestration-with-puppet-bolt/</guid>
				<description>&lt;p&gt;As discussed in the introductory post &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-bolt-with-a-puppet-control-repository/&#34;&gt;one of the use-cases for Puppet Bolt is orchestration&lt;/a&gt; - running actions on multiple targets in a certain order, possibly using results of actions or data from some targets on other targets. Orchestration with Bolt plans is quite easy: you just create a plan with multiple TargetSpec parameters, each representing a target or a type of target. A classic example is &lt;a href=&#34;https://puppet.com/blog/introducing-masterless-puppet-bolt/&#34;&gt;two or more web servers behind a load balancer&lt;/a&gt;. In this case we do something even simpler and just take a fact from a node called &amp;ldquo;first&amp;rdquo; and create a file on node &amp;ldquo;second&amp;rdquo; that uses the value of that fact in a file.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet types and providers development part 2: creating a resource</title>
				<link>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-2-creating-a-resource/</link>
				<pubDate>Sat, 07 Mar 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-2-creating-a-resource/</guid>
				<description>&lt;p&gt;This blog post is a part of this blog post series:&lt;/p&gt;&#xA;&lt;p&gt;In the &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-1-creating-the-type/&#34;&gt;previous blog post&lt;/a&gt; we created the Puppet type &lt;em&gt;librenms_service&lt;/em&gt; and created a dummy skeleton for the provider implementation. We were able to use the type, but it did not yet do anything. In this blog post we move to implementing the &lt;em&gt;create&lt;/em&gt; method, which in this case was the low-hanging fruit. At this point we do not need to worry about any existence checks (the &lt;em&gt;exists?&lt;/em&gt; method) or trying to minimizing the number of API calls with self.prefetch or something similar.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet types and providers development part 1: creating the type</title>
				<link>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-1-creating-the-type/</link>
				<pubDate>Tue, 03 Mar 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-types-and-providers-development-part-1-creating-the-type/</guid>
				<description>&lt;p&gt;This article is a part of this blog post series:&lt;/p&gt;&#xA;&lt;p&gt;Writing Puppet types and providers looks like black magic even to those who have lots of experience in the Puppet language itself. While the official &lt;a href=&#34;https://puppet.com/docs/puppet/latest/custom_types.html&#34;&gt;types development documentation&lt;/a&gt; is quite ok, &lt;a href=&#34;https://puppet.com/docs/puppet/latest/provider_development.html&#34;&gt;provider documentation&lt;/a&gt; is definitely lacking. Not only are there no practical examples from real life, the important features such as prefetching, resource methods and flushing are described only on a very high level. The usual answer to lack of examples is &amp;ldquo;have a look at the built-in resources&amp;rdquo;. But when you look at any built-in resource, you realize that the code is very complex because&lt;/p&gt;</description>
			</item>
			<item>
				<title>Giving special treatment to the last entry when iterating over a Puppet hash</title>
				<link>https://www.puppeteers.net/blog/giving-special-treatment-to-the-last-entry-when-iterating-over-a-puppet-hash/</link>
				<pubDate>Thu, 20 Feb 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/giving-special-treatment-to-the-last-entry-when-iterating-over-a-puppet-hash/</guid>
				<description>&lt;p&gt;When you&amp;rsquo;re iterating over a hash you may end up having to treat the last hash entry differently. For example, if you&amp;rsquo;re creating entries to a JSON file you should have &amp;ldquo;},&amp;rdquo; in between the entries &lt;em&gt;until&lt;/em&gt; you reach the last entry, where you &lt;em&gt;must&lt;/em&gt; have just &amp;ldquo;}&amp;rdquo; or JSON data will be invalid.&lt;/p&gt;&#xA;&lt;p&gt;Now, hashes do not have indexes, nor does Puppet support variable reassignment along the lines of $x = $x +1, so you&amp;rsquo;re out of luck trying to get the length and comparing that to a counter. So, you need some other way to detect when iteration has reached the last entry in the hash.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Debugging rspec-puppet</title>
				<link>https://www.puppeteers.net/blog/debugging-rspec-puppet/</link>
				<pubDate>Fri, 07 Feb 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/debugging-rspec-puppet/</guid>
				<description>&lt;p&gt;Usually writing rspec-puppet tests is straightforward. Then you run into some problem that does not make any sense. In my case I ran into a couple of duplicate resource declaration issues when adding rspec tests to our &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-puppetmaster&#34;&gt;puppetmaster-installer&lt;/a&gt;. The error message was not that useful:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ pdk test unit --tests=spec/classes/puppetboard_spec.rb&#xA;--- snip ---&#xA; Failures:&#xA; 1) puppetmaster::puppetboard minimal settings on ubuntu-18.04-x86_64 is expected&#xA;    to compile into a catalogue without dependency cycles&#xA;    Failure/Error: it { is_expected.to compile }&#xA;      error during compilation: Evaluation Error: Error while evaluating a&#xA;      Resource Statement, Duplicate declaration: Class[Apache] is already&#xA;      declared; cannot redeclare (file: /home/samuli/opt/puppeteers/puppet-&#xA;      puppetmaster/spec/fixtures/modules/puppetmaster/manifests/puppetboard.pp,&#xA;      line: 156) (file: /home/samuli/opt/puppeteers/puppet-puppetmaster&#xA;      /spec/fixtures/modules/puppetmaster/manifests/puppetboard.pp, line: 156,&#xA;      column: 3) on node puppet.example.org&#xA;--- snip ---&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;That particular block of code in &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-puppetmaster/blob/master/manifests/puppetboard.pp&#34;&gt;puppetboard.pp&lt;/a&gt; did include a parameterized call to the apache class. But nothing else (afaics) included that class. Also, in Vagrant the same code worked just fine, which made things seem even more bizarre. To add insult to the injury the error message did not tell where &lt;em&gt;else&lt;/em&gt; the apache class was included. That would probably have been way too helpful.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform: Importing resources from a non-default AWS region</title>
				<link>https://www.puppeteers.net/blog/terraform-importing-resources-from-a-non-default-aws-region/</link>
				<pubDate>Tue, 04 Feb 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-importing-resources-from-a-non-default-aws-region/</guid>
				<description>&lt;p&gt;I recently - again - had to import resources to Terraform (0.11.14) from AWS that were outside of the default AWS region and were managed in a nested (non-root) module. The root module contained the provider configuration, including multiple aliases to allow creation of resources in different regions, as well as the nested module call, here in a very simple version:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;provider &amp;#34;aws&amp;#34; {&#xA;  region = &amp;#34;us-west-2&amp;#34;&#xA;}&#xA;&#xA;provider &amp;#34;aws&amp;#34; {&#xA;  region = &amp;#34;us-east-1&amp;#34;&#xA;  alias  = &amp;#34;us-east-1&amp;#34;&#xA;}&#xA;&#xA;provider &amp;#34;aws&amp;#34; {&#xA;  region = &amp;#34;us-west-2&amp;#34;&#xA;  alias  = &amp;#34;us-west-2&amp;#34;&#xA;}&#xA;&#xA;module &amp;#34;cloud&amp;#34; {&#xA;  param = value&#xA;}&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;The goal was to import some &lt;a href=&#34;https://www.terraform.io/docs/providers/aws/r/ses_email_identity.html&#34;&gt;aws_ses_email_identity&lt;/a&gt; resources into the &amp;ldquo;cloud&amp;rdquo; module. So, originally the cloud module had this:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Managing Jenkins with Puppet, part 1: Basic installation</title>
				<link>https://www.puppeteers.net/blog/managing-jenkins-with-puppet-part-1/</link>
				<pubDate>Fri, 31 Jan 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/managing-jenkins-with-puppet-part-1/</guid>
				<description>&lt;p&gt;It seems every other organization is using Jenkins these days. Jenkins is a continuous integration and continuous delivery server that can be used to automate building, testing, and delivering or deploying software. &lt;/p&gt;&#xA;&lt;p&gt;Many organizations also use Puppet for their configuration management needs. Puppet is, if not the de facto configuration management solution, at least one of the most mature and field tested ones. It consists of several server components, agents, a declarative programming language, amongst others. Puppet can be used to install, set up and manage large number of all kinds of resources.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Modifying XML files with Puppet&#39;s Augeas resource</title>
				<link>https://www.puppeteers.net/blog/modifying-xml-files-with-puppets-augeas-resource/</link>
				<pubDate>Fri, 31 Jan 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/modifying-xml-files-with-puppets-augeas-resource/</guid>
				<description>&lt;p&gt;This article is based on an &lt;a href=&#34;https://www.puppeteers.net/blog/xml-tiedostojen-muokkaus-puppetin-augeas-resurssilla/&#34;&gt;earlier article&lt;/a&gt; written in Finnish.&lt;/p&gt;&#xA;&lt;p&gt;Here I describe how to make changes to an XML file with Augeas - a useful approach when managing the whole file as a template is out of the question. The configuration file used as an example, web.xml, belong to &lt;a href=&#34;https://github.com/pwm-project/pwm&#34;&gt;Pwm&lt;/a&gt;, and we intend to set the webapp context parameter.&lt;/p&gt;&#xA;&lt;p&gt;As discussed before it is important to get an idea of how Augeas sees the file before attempting to modify it with Puppet. First we tell which Augeas lens to use (here: Xml) and which file(s) to associate with the Xml lens. This can be done with in one step:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Using Augeas to manage resources in Puppet</title>
				<link>https://www.puppeteers.net/blog/using-augeas-to-manage-resources-in-puppet/</link>
				<pubDate>Fri, 31 Jan 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/using-augeas-to-manage-resources-in-puppet/</guid>
				<description>&lt;p&gt;This translated from the original Finnish article that is available &lt;a href=&#34;https://www.puppeteers.net/blog/augeas-resurssien-luonnista-ja-debuggaamisesta/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The Augeas resource in Puppet allows one to manage parts of a complex configuration file instead of managing the whole file using a template or a static file. For trivial cases stdlib&amp;rsquo;s &lt;a href=&#34;https://github.com/puppetlabs/puppetlabs-stdlib/blob/master/REFERENCE.md#file_line&#34;&gt;file_line resource&lt;/a&gt; may be sufficient. While use of templates or static files is in general more reliable and easier than use of Augeas, the latter is quite useful in many cases. As using Puppet Augeas resource directly is quite challenging, a useful practice is to first make the changes manually with &amp;ldquo;augtool&amp;rdquo; and only then convert the results into Puppet Augeas resources. We use PostgreSQL&amp;rsquo;s pg_hba.conf file here as an example.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Allowing changes to a Puppet-managed resource outside of Puppet</title>
				<link>https://www.puppeteers.net/blog/allowing-changes-to-a-puppet-managed-resource-outside-of-puppet/</link>
				<pubDate>Wed, 29 Jan 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/allowing-changes-to-a-puppet-managed-resource-outside-of-puppet/</guid>
				<description>&lt;p&gt;When a resource is managed by Puppet it is typically managed fully, or not at all. Exceptions to this rule, such as the &amp;ldquo;replace&amp;rdquo; parameter in the &lt;a href=&#34;https://puppet.com/docs/puppet/5.5/type.html#file-attribute-replace&#34;&gt;File resource&lt;/a&gt;, are rare. However, sometimes you end up having to change the properties of a resource outside of Puppet &lt;em&gt;without&lt;/em&gt; making Puppet overwrite those changes on the next run. A good example is a set of firewall rules managed with &lt;a href=&#34;https://forge.puppet.com/puppetlabs/firewall&#34;&gt;puppetlabs-firewall&lt;/a&gt; - you generally want to manage the whole ruleset with Puppet so that you can be sure of the state of the ruleset. For example, if you have libvirt installed, a bunch of virbr0-related rules may appear without your consent. On RedHat-based distros you may also see several rules getting removed by puppetlabs-firewall. Or a fellow sysadmin may have added some random iptables rules for debugging purposes. These are good reasons to have&lt;/p&gt;</description>
			</item>
			<item>
				<title>Getting the interface that matches an IP in Puppet</title>
				<link>https://www.puppeteers.net/blog/getting-the-interface-that-matches-an-ip-in-puppet/</link>
				<pubDate>Tue, 14 Jan 2020 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/getting-the-interface-that-matches-an-ip-in-puppet/</guid>
				<description>&lt;p&gt;I was recently in a situation where I needed to figure out which interface name matched a particular, static IPv4 address. On a single or a handful of nodes this could have been hardcoded in Hiera, for example, but there were dozens of nodes. The way I solved this was by creating a custom fact that uses the IPv4 address and loops through the interfaces list to find the matching interface name:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Why modules in Puppetfile should be sorted</title>
				<link>https://www.puppeteers.net/blog/why-modules-in-puppetfile-should-be-sorted/</link>
				<pubDate>Mon, 30 Dec 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/why-modules-in-puppetfile-should-be-sorted/</guid>
				<description>&lt;p&gt;This is probably one of the shortest blog postings in the history of this blog. But as this topic does not seem to be covered in more generic articles about avoiding Git merge conflicts (e.g. &lt;a href=&#34;https://geshan.com.np/blog/2016/04/3-simple-rules-for-less-or-no-git-conflicts/&#34;&gt;this&lt;/a&gt;, &lt;a href=&#34;https://medium.com/front-end-weekly/avoid-80-of-merge-conflicts-with-git-rebase-b5d755a082a6&#34;&gt;this&lt;/a&gt; and &lt;a href=&#34;https://team-coder.com/avoid-merge-conflicts/&#34;&gt;this&lt;/a&gt;), here it goes.&lt;/p&gt;&#xA;&lt;p&gt;Adding modules to the Puppetfile is a quite common task. When you or your team has multiple feature branches at the same time many of those branches may add new Puppet modules to the Puppetfile. This is fine, unless the new modules are added to the bottom of the Puppetfile: Git will get confused because it sees that multiple commits have changed the exact same place in the Puppetfile.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Pidgin IRC with ZNC and Freenode SASL external auth</title>
				<link>https://www.puppeteers.net/blog/pidgin-irc-with-znc-and-freenode-sasl-external-auth/</link>
				<pubDate>Thu, 12 Dec 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/pidgin-irc-with-znc-and-freenode-sasl-external-auth/</guid>
				<description>&lt;p&gt;I use &lt;a href=&#34;https://pidgin.im/&#34;&gt;Pidgin&lt;/a&gt; as my instant messaging client because it is open source and because it supports almost all IM protocols directly or through plugins. In my case I need support for IRC, XMPP, Facebook, Slack and SIPE (Office 365). &lt;a href=&#34;https://github.com/hoehermann/libpurple-signald&#34;&gt;Apparently&lt;/a&gt; it would be possible to use Pidgin for Signal as well, but as official Signal client is open source and works quite well I&amp;rsquo;m fine with running it standalone. As I use Linux, I can rarely hope for a native client for the proprietary IM services. Plus even if there was one, I would not want to run 4-5 messaging applications when I can have one (or two). Or to have the same amount of IM web applications open just to get messages.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet rspec testing: understanding describe and context</title>
				<link>https://www.puppeteers.net/blog/puppet-rspec-testing-understanding-describe-and-context/</link>
				<pubDate>Fri, 06 Dec 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-rspec-testing-understanding-describe-and-context/</guid>
				<description>&lt;p&gt;In the &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-module-rspec-testing-with-pdk/&#34;&gt;Puppet module rspec testing with PDK&lt;/a&gt; blog post I covered the procedure of creating and running puppet-rspec tests with PDK. This blog post will go more in-depth to that topic, in particular &lt;em&gt;describe&lt;/em&gt; and &lt;em&gt;context&lt;/em&gt; which you see in all puppet-rspec tests.&lt;/p&gt;&#xA;&lt;p&gt;When looking at the puppet-rspec test syntax the first time it looks very &amp;ldquo;rubyesque&amp;rdquo;. Somebody used to staring at Python code, for example, could call the syntax &amp;ldquo;odd&amp;rdquo; or &amp;ldquo;1337&amp;rdquo;. Fortunately reading the &lt;a href=&#34;https://relishapp.com/rspec&#34;&gt;Ruby rspec documentation&lt;/a&gt; helps understand what is going on under the hood and thus making the spec files look less magical. In my case rspec documentation helped understand how contexts work. In the &lt;a href=&#34;https://www.puppeteers.net/blog/puppet-module-rspec-testing-with-pdk/&#34;&gt;previous blog post&lt;/a&gt; a context was created for every supported operating system listed in metadata, and rspec tests were run for each of them by using facts from facterdb.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Testing Puppet feature branches in Foreman</title>
				<link>https://www.puppeteers.net/blog/testing-puppet-feature-branches-in-foreman/</link>
				<pubDate>Tue, 26 Nov 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/testing-puppet-feature-branches-in-foreman/</guid>
				<description>&lt;p&gt;With default settings &lt;a href=&#34;https://theforeman.org/&#34;&gt;Foreman&lt;/a&gt; does not allow Puppet Agents to specify their own environment when connecting to the Puppetserver. This makes it impossible to use r10k and feature branch workflow like you can with a normal Puppetserver. This behavior can fortunately be reverted easily by modifying Foreman configuration file, &lt;em&gt;/etc/foreman/settings.yaml&lt;/em&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# Allow testing feature branches on nodes&#xA;:enc_environment: false&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;After modifying settings restart the webserver, e.g.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Migrating from Fabric 1 to Fabric 2</title>
				<link>https://www.puppeteers.net/blog/migrating-from-fabric-1-to-fabric-2/</link>
				<pubDate>Thu, 10 Oct 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/migrating-from-fabric-1-to-fabric-2/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.fabfile.org/&#34;&gt;Fabric&lt;/a&gt; is a Python library for executing shell commands remotely over SSH in serial or parallel mode. I used Fabric 1 for years and it was - and still is - an excellent tool. While Fabric&amp;rsquo;s use-cases overlap somewhat with those of &lt;a href=&#34;https://www.ansible.com/&#34;&gt;Ansible&lt;/a&gt;, the difference is that Fabric &lt;em&gt;is not&lt;/em&gt; state-based. In other words, in Fabric you don&amp;rsquo;t tell that &amp;ldquo;file a should have contents n and mode m&amp;rdquo;. Instead, you just run commands on the target host which hopefully result in the end state you&amp;rsquo;re looking for. Or maybe you&amp;rsquo;re not even interested in end-state per se, but just need to run some commands. Both approaches have their use-cases. Fabric and Ansible are quite powerful as orchestration tools: they allow running task a on server x, then task b on server y. For enforcing infrastructure to be in a certain state we prefer &lt;a href=&#34;https://puppet.com/download-open-source-puppet&#34;&gt;Puppet&lt;/a&gt; and &lt;a href=&#34;https://www.terraform.io/&#34;&gt;Terraform&lt;/a&gt; over Ansible.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Explicit high-level dependencies in Puppet</title>
				<link>https://www.puppeteers.net/blog/overusing-the-anchor-pattern/</link>
				<pubDate>Wed, 09 Oct 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/overusing-the-anchor-pattern/</guid>
				<description>&lt;p&gt;I&amp;rsquo;ve noticed that some people - I won&amp;rsquo;t reveal their names here to protect them - love using contain and/or ordering arrows in Puppet. A typical use-case is for role classes:&lt;/p&gt;&#xA;&lt;p&gt;class role::webserver {&#xA;contain ::packetfilter::endpoint&#xA;contain ::profile::monit&#xA;contain ::profile::unixbase&#xA;contain ::profile::ipa_client&#xA;contain ::profile::webserver&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;Class[::packetfilter::endpoint]&lt;/code&gt;&#xA;&lt;code&gt;-&amp;gt; Class[::profile::monit]&lt;/code&gt;&#xA;&lt;code&gt;-&amp;gt; Class[::profile::unixbase]&lt;/code&gt;&#xA;&lt;code&gt;-&amp;gt; Class[::profile::ipa_client]&lt;/code&gt;&#xA;&lt;code&gt;-&amp;gt; Class[::profile::webserver]&lt;/code&gt;&#xA;}&lt;/p&gt;&#xA;&lt;p&gt;The above code nicely ensures that all the classes get applied in the exact order defined above. What happens under the hood is that Puppet generates dependencies between the classes and applies them in order.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Reprovisioning bare metal Linux servers with Foreman and IPMI</title>
				<link>https://www.puppeteers.net/blog/reprovisioning-bare-metal-linux-servers-with-foreman-and-ipmi/</link>
				<pubDate>Wed, 25 Sep 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/reprovisioning-bare-metal-linux-servers-with-foreman-and-ipmi/</guid>
				<description>&lt;p&gt;Recently we had to reprovision a bare metal server that was in Foreman and had IPMI support. The goal was to check if our automated &amp;ldquo;force-join to FreeIPA domain after reprovisioning&amp;rdquo; logic worked as intented. We did not have access to any graphical IPMI console, nor Foreman&amp;rsquo;s GUI, so we had to do everything from the command-line. The host we reprovisioned was a CentOS 7 instance. It is assumed that &lt;a href=&#34;https://community.pivotal.io/s/article/How-to-work-on-IPMI-and-IPMITOOL&#34;&gt;IPMI tools are installed&lt;/a&gt;. This post was inspired by the &lt;a href=&#34;https://hobo.house/2016/08/10/automate-supermicro-server-provisioning-or-die-trying/&#34;&gt;Automate SuperMicro Server Provisioning or Die Trying&lt;/a&gt; blog post.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Enabling PHP 7.4 on CentOS 7 with Puppet</title>
				<link>https://www.puppeteers.net/blog/enabling-php-7-4-on-centos-7-with-puppet/</link>
				<pubDate>Tue, 17 Sep 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/enabling-php-7-4-on-centos-7-with-puppet/</guid>
				<description>&lt;p&gt;The PHP version comes in default CentOS 7 repositories is rather horribly outdated. This is problematic when running Wordpress, which has to be upgraded constantly, and really old PHP versions may not be accepted, security-patched or not. The solution is to get updated PHP from the &lt;a href=&#34;https://rpms.remirepo.net/&#34;&gt;remi yum repositories.&lt;/a&gt; There are two sets of PHP packages &lt;a href=&#34;https://blog.remirepo.net/pages/English-FAQ#scl&#34;&gt;as described here&lt;/a&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Install updated packages that replace the old PHP 5 packages (i.e. names are the same)&lt;/p&gt;</description>
			</item>
			<item>
				<title>Terraform S3 access denied problems</title>
				<link>https://www.puppeteers.net/blog/terraform-s3-access-denied-problems/</link>
				<pubDate>Wed, 11 Sep 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/terraform-s3-access-denied-problems/</guid>
				<description>&lt;p&gt;I&amp;rsquo;ve stumbled upon interesting access denied problems with S3-based Terraform state files recently. Suppose you have two or more Terraform root modules which use the same bucket for storing the state and just use a different key (=state file):&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;terraform {   backend &amp;#34;s3&amp;#34; {     bucket = &amp;#34;terraform-state&amp;#34;     key    = &amp;#34;root-module-1&amp;#34;     region = &amp;#34;eu-central-1&amp;#34;   } }&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;and&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;terraform {   backend &amp;#34;s3&amp;#34; {     bucket = &amp;#34;terraform-state&amp;#34;     key    = &amp;#34;root-module-2&amp;#34;     region = &amp;#34;eu-central-1&amp;#34;   } }&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;However, trying to access the state file in one root module works, but on the other you get a generic S3 Access Denied error:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet module rspec testing with PDK</title>
				<link>https://www.puppeteers.net/blog/puppet-module-rspec-testing-with-pdk/</link>
				<pubDate>Thu, 05 Sep 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-module-rspec-testing-with-pdk/</guid>
				<description>&lt;p&gt;If you&amp;rsquo;ve searched for instructions on how to write unit tests for Puppet code you&amp;rsquo;ve probably stumbled upon tutorials such as &lt;a href=&#34;https://puppet.com/blog/next-generation-of-puppet-module-testing&#34;&gt;this&lt;/a&gt; that are of good quality, but suggest installing and using tools such as puppetlabs_rspec_helper directly. Or you may encounter references to &lt;a href=&#34;https://github.com/ruby/rake&#34;&gt;rake&lt;/a&gt;, &lt;a href=&#34;https://bundler.io/&#34;&gt;bundler&lt;/a&gt;, &lt;a href=&#34;https://rvm.io/&#34;&gt;rvm&lt;/a&gt; and &lt;a href=&#34;https://rspec.info/&#34;&gt;rspec&lt;/a&gt;. Then you start experimenting these tools, some of which (rvm and bundler) are aimed at managing the dependency hell that arises when you, or your team, works simultaneously on multiple projects with different dependency requirements. In the end you are maybe able to run spec tests on your Puppet module, but after all installations of gems and experiments you&amp;rsquo;re unsure what you did to make everything work. You also don&amp;rsquo;t want to become a hard-core Ruby developer who actually understands all these tools well - you just want to test your Puppet code.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lack of default connection settings in Terraform 0.12.x</title>
				<link>https://www.puppeteers.net/blog/lack-of-default-connection-settings-in-terraform-0-12-x/</link>
				<pubDate>Thu, 29 Aug 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/lack-of-default-connection-settings-in-terraform-0-12-x/</guid>
				<description>&lt;p&gt;I was recently bit by a feature (one might call it a bug) in Terraform. We wanted to try out the &amp;ldquo;Networks&amp;rdquo; feature in &lt;a href=&#34;https://www.hetzner.com/cloud&#34;&gt;Hetzner Cloud&lt;/a&gt; but that required upgrading &lt;a href=&#34;https://github.com/terraform-providers/terraform-provider-hcloud&#34;&gt;terraform-provider-hcloud&lt;/a&gt;, which in turn required upgrading Terraform to 0.12.x. For the most part migration from 0.11.x code to 0.12.x code was straightforward with some help from the automated migration tool. I even went as far as read some of the migration documentation, but missed one important part: &lt;a href=&#34;https://www.terraform.io/upgrade-guides/0-12.html#default-settings-in-connection-blocks&#34;&gt;connection blocks no longer have default values.&lt;/a&gt; To make the matter worse Terraform 0.12 does not error out if values are unset: instead if just runs the provisioner and then times out. This seems to be related to &lt;a href=&#34;https://github.com/hashicorp/terraform/issues/21690&#34;&gt;Terraform bug #21690&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Moving Jenkins user home directory</title>
				<link>https://www.puppeteers.net/blog/moving-jenkins-user-home-directory/</link>
				<pubDate>Thu, 29 Aug 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/moving-jenkins-user-home-directory/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://jenkins.io/&#34;&gt;Jenkins&lt;/a&gt; is a continuous integration (CI) / continuous delivery (CD) platform consisting of a Jenkins master - essentially a controller - which launches jobs on Jenkins slaves. Often slaves are controlled via SSH.&lt;/p&gt;&#xA;&lt;p&gt;Recently I ran into an issue with a legacy Jenkins slave where the &amp;ldquo;jenkins&amp;rdquo; where Puppet tried to enforce the home directory of &amp;ldquo;jenkins&amp;rdquo; to be /home/jenkins instead of /var/lib/jenkins:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Error: Could not set home on user[jenkins]: Execution of &amp;#39;/usr/sbin/usermod -d /home/jenkins jenkins&amp;#39; returned 8: usermod: user jenkins is currently used by p rocess 802  &lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;The usermod command failed because several Jenkins processes (ssh-agent, Java) locked the user from modification. The solution was relatively straightforward:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Foreman and the Puppetserver environment cache</title>
				<link>https://www.puppeteers.net/blog/foreman-and-the-puppetserver-environment-cache/</link>
				<pubDate>Sat, 17 Aug 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/foreman-and-the-puppetserver-environment-cache/</guid>
				<description>&lt;p&gt;Importing classes is a two-phase process when you&amp;rsquo;re using r10k with Foreman. Say you&amp;rsquo;ve created a new class, &amp;ldquo;role::ipa_server&amp;rdquo; to the &amp;ldquo;production&amp;rdquo; environment; without Foreman it would be sufficient to deploy the change on the Puppetserver with r10k:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ r10k deploy environment production -vp&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;At this point Foreman does not, however, know anything about this new class deployed with r10k:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ hammer puppet-class list --environment production|grep ipa_server&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;The &amp;ldquo;Smart proxy&amp;rdquo; component in Foreman - also known as &amp;ldquo;foreman-proxy&amp;rdquo; - is responsible for fetching new classes from Puppetserver. With the latest Puppet versions it uses the Puppetserver API to do the import. It is fairly trivial to update Foreman&amp;rsquo;s list of classes using the command-line&lt;/p&gt;</description>
			</item>
			<item>
				<title>Foreman ja puppetserverin environment cache</title>
				<link>https://www.puppeteers.net/blog/foreman-ja-puppetserverin-environment-cache/</link>
				<pubDate>Wed, 07 Aug 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/foreman-ja-puppetserverin-environment-cache/</guid>
				<description>&lt;p&gt;Kun käytetään r10k:ta ja Foremania yhdessä on uusien luokkien tuonti kaksivaiheinen prosessi. Oletetaan vaikka, että &amp;ldquo;production&amp;rdquo; environmentiin on luotu uusi luokka, esim. &amp;ldquo;role::ipa_server&amp;rdquo;. Ilman Foremania riittäisi tuoda muutos puppetmasterille r10k:lla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ r10k deploy environment production -vp&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Foreman ei kuitenkaan vielä tiedä uudesta luokasta mitään:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ hammer puppet-class list --environment production|grep ipa_server&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Foremanin komponentti, joka hakee Puppetmasterilta uudet luokat on nimeltään &amp;ldquo;Smart proxy&amp;rdquo;, joka tunnetaan myös nimellä &amp;ldquo;foreman-proxy&amp;rdquo;. Uusimpien Puppetin versioiden kanssa se hakee luokat Puppetserverin API:a käyttäen. Luokat saa päivitettyä komentoriviltä melko triviaalisti:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Neulan erottaminen Git-muutosten heinäsuovasta</title>
				<link>https://www.puppeteers.net/blog/neulan-erottaminen-git-muutosten-heinasuovasta/</link>
				<pubDate>Mon, 15 Jul 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/neulan-erottaminen-git-muutosten-heinasuovasta/</guid>
				<description>&lt;p&gt;Toisinaan käy niin, että on tarpeen varmistua siitä aiheuttaako iso kasa Git-committeja jotain sivuvaikutuksia esimerkiksi Puppet-tuotantoympäristössä. Hyvistä commit-viesteistä on aina toki apua, mutta toisinaan commitit eivät ole täysin atomisia, eli tekevät enemmän kuin yhden (dokumentoidun) asian. Lisäksi esimerkiksi Puppet control reposta saattaa löytyä paitsi Puppet-koodia, myös Terraformia ja Ansiblea. Tälläisessä tapauksessa on kätevää näyttää vain muutokset, jotka ovat oikeasti relevantteja. Ensin tarkistetaan, mikä &amp;ldquo;production&amp;rdquo;-ympäristön viimeisin commit on:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ssh puppet$ cd /etc/puppetlabs/code/environments/production$ git rev-parse --short HEAD86c2152&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tämän jälkeen voidaan tarkista control reposta muutokset Puppetin kannalta oleellisiin kansioihin ja tiedostoihin:&lt;/p&gt;</description>
			</item>
			<item>
				<title>FreeIPA:an liitettyjen hostien SSH-avaimien päivitys</title>
				<link>https://www.puppeteers.net/blog/freeipaan-liitettyjen-hostien-ssh-avaimien-paivitys/</link>
				<pubDate>Thu, 07 Feb 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/freeipaan-liitettyjen-hostien-ssh-avaimien-paivitys/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.freeipa.org/page/Main_Page&#34;&gt;FreeIPA&lt;/a&gt; on Linux-verkkojen &amp;ldquo;Active Directory&amp;rdquo;, jossa on integroitu lukuisia eri komponentteja (mm. LDAP, Kerberos, CA, sssd) siten, että Linux-koneet saadaan liitettyä domainiin. Domainiin liittäminen mahdollistaa mm. keskitetyt käyttäjätunnukset, kertakirjautumisen ja SSH-avaimien ja SSH host-avaimien jakelun. FreeIPA:n voi pystyttää sen omalla asennusohjelmalla, johon iso osa myös &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-ipa&#34;&gt;puppet-ipa&lt;/a&gt; moduulin toiminnallisuudesta perustuu.&lt;/p&gt;&#xA;&lt;p&gt;FreeIPA:ssa on kuitenkin yksi pieni ärsyttävyys: mikäli noodi (esim. palvelin) rakennetaan (esim. AWS EC2 snapshotista) tai provisioidaan (esim. PXE boot) uudelleen, saattavat FreeIPA:ssa säilytettävät SSH host-avaimet mennä epäsynkkaan todellisuuden kanssa. Käytännössä koneelle ei enää silloin pääse kirjautumaan ilman SSH:n tietoturvamekanismien härskiä kiertämistä:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppeteersin Puppetmaster installer-tuote nyt AWS:ssä</title>
				<link>https://www.puppeteers.net/blog/puppeteersin-puppetmaster-installer-tuote-nyt-awsssa/</link>
				<pubDate>Mon, 07 Jan 2019 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppeteersin-puppetmaster-installer-tuote-nyt-awsssa/</guid>
				<description>&lt;p&gt;&lt;strong&gt;HUOM: Tuote on poistunut!&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;Pitkällisen kehitystyön tuloksena saimme kuin saimmekin tehtyä Puppetmasterin Kafo-pohjaisesta asentimestamme oikean AWS Marketplace-tuotteen: Configuration Manager By Puppeteers Oy.&lt;/p&gt;&#xA;&lt;p&gt;Tuotteen hinnoittelu perustuu käyttötunteihin. Tuote tukee kolmea eri skenaariota:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Pelkkä Puppetserver&lt;/li&gt;&#xA;&lt;li&gt;Puppetserver ja PuppetDB&lt;/li&gt;&#xA;&lt;li&gt;Puppetserver, PuppetDB ja Puppetboard&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Installer tekee aiemmin jokseenkin rasittavasti Puppetmasterien asentelusta suorastaan naurettavan helppoa:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ssh -i ~/.ssh/mykey.pem ubuntu@instance-ip&#xA; $ sudo -i&#xA; $ puppetmaster-installer -i&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tämän jälkeen valitaan skenaario ja mahdollisesti muutetaan joitain parametreja ja ajetaan asennin. PuppetDB:n ja Puppetboardin salasanat luodaan automaattisesti jos niitä ei ole määritetty.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet-moduulien dokumentaation automaattinen päivittäminen</title>
				<link>https://www.puppeteers.net/blog/puppet-moduulien-dokumentaation-automaattinen-paivittaminen/</link>
				<pubDate>Mon, 19 Nov 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-moduulien-dokumentaation-automaattinen-paivittaminen/</guid>
				<description>&lt;p&gt;Puppet-moduulien dokumentaation saa helposti päivitettyä &lt;a href=&#34;https://github.com/puppetlabs/puppet-strings&#34;&gt;&amp;ldquo;puppet strings&amp;rdquo;-työkalulla&lt;/a&gt;, jonka käyttö yleisellä tasolla on dokumentoitu &lt;a href=&#34;https://puppet.com/docs/puppet/6.0/puppet_strings.html&#34;&gt;varsin hyvin&lt;/a&gt;. Kun komento vielä yhdistetään Gitin pre-commit -hookiin, saadaan dokumentaatio päivitettyä automaattisesti joka commitilla. Alla näytetään, miten tämä saadaan toteutettua niin Linuxissa kuin Windowsissa. Oletuksena on, että molemmissa tapauksissa Puppet Agent 5.x on asennettu virallisista Puppetlabsin paketeista.&lt;/p&gt;&#xA;&lt;p&gt;Aloitan helpommasta eli Linuxista käyttäen esimerkkinä Debian 9:iä: ohjeiden pitäisi kuitenkin toimia myös Ubuntuissa aivan samalla tavoin. Ensin asennetaan Git:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ sudo -s&#xA; $ apt-get update &amp;amp;&amp;amp; apt-get install git&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Sen jälkeen asennetaan tarvittavat gemmit käyttäen Puppetin gem-komentoa:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Kansioiden siistiminen turhasta tauhkasta Powershellillä</title>
				<link>https://www.puppeteers.net/blog/kansioiden-siistiminen-turhasta-tauhkasta-powershellilla/</link>
				<pubDate>Wed, 08 Aug 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/kansioiden-siistiminen-turhasta-tauhkasta-powershellilla/</guid>
				<description>&lt;p&gt;Toisinaan voi tulla tarve säilyttää jonkin kansion hakemistorakenne, mutta poistaa sieltä suuria määriä tiedostoja. Näin voi käydä esimerkiksi silloin, kun halutaan säästää käännösprosessin tulokset, esim. exe-tiedostot, mutta päästä eroon lähdekoodista ja käännöksen tuottamista väliaikaistiedostoista. Tämä onnistuu kätevästi Powershellin Where-Object CmdLetillä. Alla oletetaan, että komennot ajetaan kansiosta, jonka sisältö halutaan siistiä. Lähtötilanteessa kansiossa on 91 tiedostoa ja hakemistoa:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PS&amp;gt; Get-Childitem -Recurse|Measure-Object|Select Count|Format-List&#xA; Count : 91&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Seuraavaksi poistetaan ne &lt;em&gt;ei-hakemistot&lt;/em&gt; (~tiedostot), joiden tiedostopääte &lt;em&gt;ei&lt;/em&gt; ole .exe:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Zip-arkistojen käsittely Powershellillä</title>
				<link>https://www.puppeteers.net/blog/zip-arkistojen-kasittely-powershellilla/</link>
				<pubDate>Wed, 08 Aug 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/zip-arkistojen-kasittely-powershellilla/</guid>
				<description>&lt;p&gt;Powershell 5:n myötä myös ZIP-arkistoja &lt;a href=&#34;https://www.rootusers.com/how-to-zipunzip-files-in-windows-with-powershell/&#34;&gt;voi käsitellä&lt;/a&gt; Powershellillä. Tätä aiemmin piti käyttää jos jonkinmoisia kikkoja arkistojen purkamiseen, mikä etenkin komentoriviltä työskenneltäessä oli erittäin ärsyttävää. Arkisto luodaan tähän tapaan:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PS&amp;gt; Compress-Archive -LiteralPath tap-windows6 -DestinationPath tap-windows6-9.22.3.zip&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Yleensä ottaen kohdetiedoston nimeen ei tarvitse lisätä tiedostopäätettä (.zip). Tässä tapauksessa Compress-Archive CmdLet kuitenkin hämmentyy, jos sitä ei ole:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PS&amp;gt; Compress-Archive -LiteralPath tap-windows6 -DestinationPath tap-windows6-9.22.3&#xA; Compress-Archive : .3 is not a supported archive file format. .zip is the only supported archive file format.&#xA; --- snip ---&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Syynä ovat tietenkin kohdetiedoston nimessä olevat pisteet. Compress-Archive CmdLetissä on dokumentoimaton ja jokseenkin ärsyttävä bugi tai ominaisuus: se ei lisää pisteellä alkavia piilohakemistoja arkistoon paitsi jos ne määritellään eksplisiittisesti lähdetiedostolistauksessa (-LiteralPath). Lisäksi kaikki lähdetiedostolistauksen tiedostot ja kansiot lisätään suoraan arkiston juureen, eikä niiden polkua kunnioiteta. Siis esimerkiksi&lt;/p&gt;</description>
			</item>
			<item>
				<title>Windows-ajurien tietojen näyttäminen Powershellillä</title>
				<link>https://www.puppeteers.net/blog/windows-ajurien-tietojen-nayttaminen-powershellilla/</link>
				<pubDate>Thu, 26 Jul 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/windows-ajurien-tietojen-nayttaminen-powershellilla/</guid>
				<description>&lt;p&gt;Windowsissa on useita komentorivityökaluja asennettujen ajurien tietojen selvittämiseen. Usein törmää seuraavaan komentoon:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PS&amp;gt; Get-WmiObject Win32_PnPSignedDriver&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;&lt;a href=&#34;https://msdn.microsoft.com/en-us/library/aa394354%5C%28v=vs.85%5C%29.aspx&#34;&gt;Luokka Win32_PnpSignedDriver&lt;/a&gt; sisältää tiedot ajurien digitaalisista allekirjoituksista sekä lisätietoja, kuten ajurin version. Useimmissa tapauksissa tämä komento riittää, sillä Windows ei ole Windows Vistan jälkeen suostunut lataamaan kuin kaupallisin varmentein allekirjoitettuja ajureita ilman, että se on &lt;a href=&#34;https://docs.microsoft.com/en-us/windows-hardware/drivers/install/the-testsigning-boot-configuration-option&#34;&gt;test-signing -tilassa&lt;/a&gt;. Windows 10:n mukana tuli vaatimus siitä, että ajuri sisältää &lt;a href=&#34;https://docs.microsoft.com/en-us/windows-hardware/drivers/dashboard/attestation-signing-a-kernel-driver-for-public-release&#34;&gt;Microsoftin digitaalisen allekirjoituksen&lt;/a&gt;. Windows Server 2016 vaatii myöskin Microsoftin allekirjoituksen, mutta sen saaminen ajurille vaatii lisäksi, että &lt;a href=&#34;https://docs.microsoft.com/en-us/windows-hardware/test/hlk/windows-hardware-lab-kit&#34;&gt;Windows Hardware Lab Kit&lt;/a&gt; -testit on läpäisty. Käytännössä kehitys- ja testikoneita lukuun ottamatta kaikkien ajurien voidaan siis olettaa olevan kaupallisin varmentein allekirjoitettuja.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Select-Stringin käyttö grepin korvikkeena</title>
				<link>https://www.puppeteers.net/blog/select-stringin-kaytto-grepin-korvikkeena/</link>
				<pubDate>Thu, 07 Jun 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/select-stringin-kaytto-grepin-korvikkeena/</guid>
				<description>&lt;p&gt;Kun unixeissa pitää etsiä neula tekstimuotoisen datan heinäsuovasta, käytetään yleensä &lt;em&gt;grep&lt;/em&gt;-komentoa. Jos tekstirivi täsmää annettuun hakuparametriin tulostetaan se oletustulostevirtaan (stdout). Grepin kanssa voidaan käyttää hakuparametreina yksinkertaisten merkkijonojen lisäksi säännöllisiä lausekkeita ja käyttää vaikka mitä muita hienoja kikkoja.&lt;/p&gt;&#xA;&lt;p&gt;Powershellissä ei (ilmeisesti) ole mitään näin hienoa työkalua, mutta onneksi tekstimassasta saa useimmiten seulottua esille oleellisen Select-Stringin merkkijonohaulla. Esimerkiksi Windowsissa on oletuksena palomuurisääntöjä niin valtavat määrät, että niiden kaikkien läpikäynti jonkin tietyn säännön löytämiseksi on hullun hommaa. Hommaa voi helpottaa Select-Stringillä:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Funktioiden kirjoittaminen Puppet-kielellä</title>
				<link>https://www.puppeteers.net/blog/functioniden-kirjoittaminen-puppet-kielella/</link>
				<pubDate>Wed, 23 May 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/functioniden-kirjoittaminen-puppet-kielella/</guid>
				<description>&lt;p&gt;Puppetissa on suuri määrä erilaisia rakenteita, joilla turhaa toistoa koodissa voidaan vähentää. &lt;a href=&#34;https://www.puppeteers.fi/puppet-koodin-tiivistaminen-each-functionlla-ja-resurssien-oletusarvoilla/&#34;&gt;Aiemmin&lt;/a&gt; käsiteltiin jo resurssien oletusarvoja ja each-funktiota, joilla toistoa voidaan vähentää yksittäisessä manifest-tiedostossa. Funktiolla samalle koodilohkolle voidaan välittää parametreja, joiden perusteella se laskee mekaanisesti jonkin paluuarvon. Kuten Puppetin &lt;a href=&#34;https://puppet.com/docs/puppet/5.3/function.html&#34;&gt;virallisten funktioiden listasta&lt;/a&gt; näkyy, tätä funktioiden ominaisuutta hyödynnetään mitä erilaisimpiin käyttötarkoituksiin. Funktioita voi paitsi käyttää eri manifesteissa, myös eri moduuleissa kuin missä ne on määritetty.&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://puppet.com/docs/puppet/5.3/functions_ruby_overview.html&#34;&gt;Perinteisesti&lt;/a&gt; funktioita kirjoitettiin Ruby-kielellä. Sittemmin on tullut mahdolliseksi kirjoittaa niitä myös Puppet-kielellä. Alla yksinkertainen esimerkki &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-openvpn&#34;&gt;puppetfinland/openvpn&lt;/a&gt;-moduulista:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Windowsien palomuurin hallinta Puppetilla</title>
				<link>https://www.puppeteers.net/blog/windowsien-palomuurin-hallinta-puppetilla/</link>
				<pubDate>Wed, 23 May 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/windowsien-palomuurin-hallinta-puppetilla/</guid>
				<description>&lt;p&gt;Linuxissa palomuurina - tai tarkemmin pakettisuodattimena - käytetään &lt;a href=&#34;https://www.netfilter.org/&#34;&gt;netfilteriä&lt;/a&gt;, jota hallitaan yleensä &lt;a href=&#34;https://www.netfilter.org/projects/iptables/index.html&#34;&gt;iptables&lt;/a&gt; (IPv4) ja ip6tables (IPv6) komennoilla. Iptables-sääntöjen määritys Puppetissa onnistuu helpoiten &lt;a href=&#34;https://github.com/puppetlabs/puppetlabs-firewall&#34;&gt;puppetlabs/firewall&lt;/a&gt; -moduulilla. Tyypillinen käyttötapaus on portin avaaminen palomuuriin; tästä tyypillisenä esimerkkinä Puppet-Finland-projektin &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-snmpd/blob/master/manifests/packetfilter.pp&#34;&gt;::snmp::packetfilter&lt;/a&gt; -luokka, jossa avataan pääsy UDP-portiin 161 määritetyistä IPv4 ja IPv6-osoitteista.&lt;/p&gt;&#xA;&lt;p&gt;Myös Windowsin palomuurisääntöjä voi muokata Puppetilla käyttämällä &lt;a href=&#34;https://github.com/voxpupuli/puppet-windows_firewall&#34;&gt;puppet/windows_firewall&lt;/a&gt; -moduulia. Kyseinen moduuli on melko yksinkertainen kääre &amp;ldquo;netsh advfirewall&amp;rdquo;-komennon ympärillä, mutta se hoitaa hommansa hyvin.&lt;/p&gt;&#xA;&lt;p&gt;Linuxissa koko palomuurisäännöstö on helppo pitää ruodussa Puppetilla (ks. esim. &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-packetfilter&#34;&gt;puppetfinland/packetfilter&lt;/a&gt; moduuli), mutta Windowsissa on pitkälti tyytyminen sääntöjen kevyeen lisäämiseen ja muokkaamiseen. Tämä käy ilmeiseksi, kun listaa tuoreen Windows-koneen palomuurisäännöt:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet-moduulien julkaisu Puppet Forgessa</title>
				<link>https://www.puppeteers.net/blog/puppet-moduulien-julkaisu-puppet-forgessa/</link>
				<pubDate>Wed, 02 May 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-moduulien-julkaisu-puppet-forgessa/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://forge.puppet.com/&#34;&gt;Puppet Forge&lt;/a&gt; on Puppetlabsin tarjoama repo Puppet-moduuleille. Forge-moduuleja voi asentaa &amp;ldquo;puppet module install&amp;rdquo;-komennolla, mutta niihin voi viitata myös &lt;a href=&#34;https://github.com/puppetlabs/r10k&#34;&gt;r10k:n&lt;/a&gt; tai &lt;a href=&#34;http://librarian-puppet.com/&#34;&gt;librarian-puppetin&lt;/a&gt; Puppetfilessä. Nykyisin Puppet Forge on ensimmäinen paikka, josta katson, onko joku muu jo ratkaissut käsilläni olevan ongelman Puppetilla - pyörää kun on toisinaan turha keksiä uudelleen.&lt;/p&gt;&#xA;&lt;p&gt;Olen itse käyttänyt vuosia &lt;a href=&#34;https://git-scm.com/book/en/v2/Git-Tools-Submodules&#34;&gt;Git Submoduleja&lt;/a&gt;, koska niiden avulla Puppet-moduuleihin ulkopuolelta tulevat muutokset on helppo tarkistaa Gitin lokeista ja diffeistä. Niiden käyttö menee kuitenkin kankeaksi kun moduulien määrä kasvaa suureksi: sekä päärepo että submodulet vaativat jatkuvaa paapomista. Tuloksena on turhanpäiväisiä, samankaltaisina toistuvia commit-viestejä kuten &amp;ldquo;Update Git submodule pointers&amp;rdquo;, joilla ei ole mitään muuta käytännön merkitystä kuin Gitin pitäminen tyytyväisenä.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Bashin ja Powershellin komentohistorian käyttö</title>
				<link>https://www.puppeteers.net/blog/bashin-ja-powershellin-komentohistorian-kaytto/</link>
				<pubDate>Mon, 23 Apr 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/bashin-ja-powershellin-komentohistorian-kaytto/</guid>
				<description>&lt;p&gt;Unix-komentotulkeissa kuten Bashissa on ollut vuosikaudet varsin monipuoliset tavat palata komentotulkin historiasta löytyviin komentoihin. Nuoli ylös palaa komentohistoriassa taaksepäin ja nuoli alas vie eteenpäin. Koko historian näkee komennolla &amp;ldquo;history&amp;rdquo;:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ history&#xA; 1257 git remote -v&#xA; 1258 cd /tmp/&#xA; --- snip ---&#xA; 2242 id -un 0&#xA; 2243 id -gn 0&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tämän voi yhdistää grepin kanssa:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ history|grep remote&#xA; 1264 git remote -v&#xA; --- snip --&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Yksi kätevimmistä on haku historiasta: ensin painetaan Ctrl-R ja sen jälkeen syötetään hakusana (alla &amp;ldquo;gpg&amp;rdquo;):&lt;/p&gt;</description>
			</item>
			<item>
				<title>RAL ja järjestelmän tilan muuntaminen puppet-koodiksi</title>
				<link>https://www.puppeteers.net/blog/ral-ja-jarjestelman-tilan-muuntaminen-puppet-koodiksi/</link>
				<pubDate>Mon, 23 Apr 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/ral-ja-jarjestelman-tilan-muuntaminen-puppet-koodiksi/</guid>
				<description>&lt;p&gt;Joskus käy niin että verkosta löytyy huolellisesti vuosien mittaan käsin säädetty, mahdollisesti jo edesmenneeltä sysadminilta peritty taideteos, jonka sielunelämästä ei kukaan enää ymmärrä, ja joka uhkaa romahtaa jos hengittää kohti liian kovaa. Se tuottaa mahdollisesti vielä jotakin yritykselle merkityksellistä palveluakin. Mikä avuksi?&lt;/p&gt;&#xA;&lt;p&gt;Jos näin on päässyt käymään, tai odotetaan suoritettavan muun toistaiseksi villinä ja vapaana ajelevan järjestelmän hallinta puppetilla, on hyvä palauttaa mieleen, että puppet sisältää RAL-kuoren (Resource Abstraction Layer), jonka avulla voidaan tarkastella sitä miten puppet näkee järjestelmän. RAL-kuoren avulla voidaan järjestelmän tila muuntaa puppet-koodiksi pienellä vaivalla. Esimerkiksi hakemistopuun muuntaminen:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet-koodin tiivistäminen each-funktiolla ja resurssien oletusarvoilla</title>
				<link>https://www.puppeteers.net/blog/puppet-koodin-tiivistaminen-each-functionlla-ja-resurssien-oletusarvoilla/</link>
				<pubDate>Tue, 13 Mar 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-koodin-tiivistaminen-each-functionlla-ja-resurssien-oletusarvoilla/</guid>
				<description>&lt;p&gt;Puppet-koodissa on monia tapoja vähentää koodiin määrää. Silloin, kun pitää luoda useita hyvin samankaltaisia resursseja, on &lt;a href=&#34;https://puppet.com/docs/puppet/5.3/function.html#each&#34;&gt;each-funktio&lt;/a&gt; erittäin kätevä työkalu. Jos luotavien resurssien erot rajoittuvat yhden parametrin arvoon, riittää seuraava:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# testfiles.pp&#xA; $testfiles = [&amp;#39;/tmp/foo&amp;#39;,&amp;#39;/tmp/bar&amp;#39;]&#xA; $testfiles.each |$testfile| {&#xA; file { $testfile:&#xA; ensure =&amp;gt; &amp;#39;present&amp;#39;,&#xA; }&#xA; }&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Yllä oleva koodi luo molemmat tiedostot:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ puppet apply testfiles.pp&#xA; Notice: Compiled catalog for computer.example.org in environment production in 0.13 seconds&#xA; Notice: /Stage[main]/Main/File[/tmp/foo]/ensure: created&#xA; Notice: /Stage[main]/Main/File[/tmp/bar]/ensure: created&#xA; Notice: Applied catalog in 0.03 seconds&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Each-funktio on erityisen voimallinen, kun sen käyttämä data määritetään Hash-tyyppisessä muuttujassa. Alla esimerkki ini-tiedoston muokkauksesta &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-gitdaemon&#34;&gt;gitdaemon-moduulissa&lt;/a&gt;:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Ulkoisten faktojen perusteet</title>
				<link>https://www.puppeteers.net/blog/ulkoisten-faktojen-perusteet/</link>
				<pubDate>Wed, 28 Feb 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/ulkoisten-faktojen-perusteet/</guid>
				<description>&lt;p&gt;Aiemmassa blogikirjoituksessa käsittelin &lt;a href=&#34;https://www.puppeteers.net/blog/custom-faktojen-luonti-ohjelmallisesti/&#34;&gt;custom faktojen&lt;/a&gt; luontia dynaamisesti. Tällä kertaa käsittelemme ulkoisten faktojen (&amp;ldquo;external facts&amp;rdquo;) perusteita. Puppetlabsin &lt;a href=&#34;https://puppet.com/docs/facter/3.9/custom_facts.html&#34;&gt;oma dokumentaatio aiheesta&lt;/a&gt; on varsin laadukasta, kunhan sen vain malttaa lukea ajatuksen kanssa (toisin kuin allekirjoittanut).&lt;/p&gt;&#xA;&lt;p&gt;Ulkoisilla faktoilla tarkoitetaan faktoja, joiden arvon Facter päättelee niiden tulosteesta ja joita ei tyypillisesti ole kirjoitettu Rubyllä vaan esim. Bashilla, Pythonilla tai PowerShellillä. Ne toimivat muutoin kuin &amp;ldquo;oikeat&amp;rdquo; faktat, mutta niissä ei voida viitata muihin faktoihin, eikä niitä voi rajata (&amp;ldquo;confine&amp;rdquo;) toimimaan vain jossain käyttöjärjestelmässä.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Custom faktojen luonti ohjelmallisesti</title>
				<link>https://www.puppeteers.net/blog/custom-faktojen-luonti-ohjelmallisesti/</link>
				<pubDate>Wed, 21 Feb 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/custom-faktojen-luonti-ohjelmallisesti/</guid>
				<description>&lt;p&gt;Staattisten faktojen kirjoittaminen on varsin helppoa melko vähäisinkin Ruby-taidoin. Alla esimerkki faktasta, joka palauttaa true tai false riippuen siitä, onko noodilla /boot-osiota:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;Facter.add(:has_bootfs) do&#xA; setcode do&#xA; if Facter.value(:mountpoints)[&amp;#39;/boot&amp;#39;].nil?&#xA; false&#xA; else&#xA; true&#xA; end&#xA; end&#xA; end&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Kuten yltä näkyy, itse tieto löytyi jo valmiiksi Facterin &amp;ldquo;mountpoints&amp;rdquo;-faktan sisältä: yllä sen sisältöä vain muunnettiin erilliseksi, helposti käsiteltäväksi faktaksi visualisointia ja skriptausta helpottamaan.&lt;/p&gt;&#xA;&lt;p&gt;Mountpoints-fakta sisältää myös paljon muuta kiinnostaa tietoa, kuten sen, miten suuri osio on ja paljonko siellä on tilaa vapaana. Jos näistäkin tiedoista halutaan luoda samaan tapaan erilliset faktat, voidaan ne helposti luoda dynaamisesti:&lt;/p&gt;</description>
			</item>
			<item>
				<title>XML-tiedostojen muokkaus Puppetin Augeas-resurssilla</title>
				<link>https://www.puppeteers.net/blog/xml-tiedostojen-muokkaus-puppetin-augeas-resurssilla/</link>
				<pubDate>Sun, 18 Feb 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/xml-tiedostojen-muokkaus-puppetin-augeas-resurssilla/</guid>
				<description>&lt;p&gt;NOTE: this article is now also available in English (&lt;a href=&#34;https://www.puppeteers.net/blog/modifying-xml-files-with-puppets-augeas-resource/&#34;&gt;here&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.fi/augeas-resurssien-luonnista-ja-debuggaamisesta/&#34;&gt;Aiemmassa blogikirjoituksessa&lt;/a&gt; käsittelin Augeaksen käyttöä Puppetin kanssa esimerkkinä PostgreSQL:n pg_hba.conf -tiedoston muokkaus. Tässä kirjoituksessa käsitellään XML-tiedostojen muokkausta Augeaksella, mikä on luultavasti siistein ratkaisu silloin, kun ei haluta hallita koko tiedostoa esimerkiksi ERB-templatena. Alla muokataan &lt;a href=&#34;https://github.com/pwm-project/pwm&#34;&gt;Pwm:n&lt;/a&gt; web.xml-tiedostoa, johon on määritettävä asetushakemiston polku.&lt;/p&gt;&#xA;&lt;p&gt;Ennen itse Augeas-resurssin kirjoitusta kannattaa tarkistaa, mikä Augeaksen käsitys muokattavan tiedoston rakenteesta on. Ensin augtoolille pitää kertoa, mistä hallittava tiedosto löytyy:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lisää läskiä työnkulkuun, osa 5: Hiera ja sisällön kryptaaminen</title>
				<link>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-5-hiera-ja-sisallon-kryptaaminen/</link>
				<pubDate>Mon, 05 Feb 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-5-hiera-ja-sisallon-kryptaaminen/</guid>
				<description>&lt;p&gt;Puppet-moduulien ja manifestien uudelleenkäytettävyyden vuoksi on suositeltavaa pitää data niistä erillään. Tämä tapahtuu käyttämällä hieraa. Moduulit voivat esimerkiksi tuottaa erilaisia asetuksia käyttämällä hieran perusteella organisaatiohin tai sijainteihin määriteltyä dataa&lt;/p&gt;&#xA;&lt;p&gt;Hieraan tallennetaan tyypillisesti myös sellaista yksityistä dataa mikä pitää olla suojattua, ja minkä ei haluta joutuvan ulkopuolisten saataville. Tyypillisesti data tallennetaan muun koodin ohella versionhallintajärjestelmään, joka voi olla organisaation rajojen ulkopuolella. Tällöin on käytettävä hieran encryptionta.&lt;/p&gt;&#xA;&lt;p&gt;Aiemmin yleisesti käytetty hieran salauksen menetelmä oli hiera-gpg. Hiera-gpg:n avulla salattiin koko tiedosto. Hiera-eyaml parantaa tilannetta sallimalla hieratiedoston sisällä haluttujen datalohkojen salaamisen, mikä parantaa käytettävyyttä.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Yleiskatsaus moderniin Puppet 5 ympäristöön</title>
				<link>https://www.puppeteers.net/blog/yleiskatsaus-moderniin-puppet-5-ymparistoon/</link>
				<pubDate>Mon, 05 Feb 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/yleiskatsaus-moderniin-puppet-5-ymparistoon/</guid>
				<description>&lt;p&gt;Puppetin palvelinpuoleen kuuluu on nykyisin aikamoinen tukku palvelinsovelluksia, työkaluja ja suositeltuja työnkulkuja:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;strong&gt;Palvelinkomponentit&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Puppetserver:&lt;/strong&gt; Varsinainen Puppet-palvelin, johon Puppet agentit ottavat yhteyttä. Toimii myös itsenäisesti ilman PuppetDB:tä ja Puppetboardia&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;PuppetDB:&lt;/strong&gt; Datasäilö, johon Puppet agentit tallentavat faktojaan ja raporttejaan. Dataan päästään haluttaessa käsin ohjelmallisesti.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;PostgreSQL:&lt;/strong&gt; PuppetDB:n taustalla oleva tietokantapalvelin&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Puppetboard:&lt;/strong&gt; PuppetDB:n datan visualisoitiin tarkoitettu webbisovellus.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Apache 2:&lt;/strong&gt; Puppetboardin taustalla oleva webbipalvelin&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Työkalut&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Git:&lt;/strong&gt; versionhallintajärjestelmä, josta &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/&#34;&gt;hallintarepo&lt;/a&gt;, &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-2-r10k/&#34;&gt;r10k&lt;/a&gt; ja monien Puppet moduulien käyttö on riippuvaista.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Hiera:&lt;/strong&gt; hierarkinen datasäilö Puppet-moduulien, esim. &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-4-roolit-ja-profiilit/&#34;&gt;profiilien&lt;/a&gt;, parametreille. Voidaan käyttää asiakaskoneiden asetusten räätälöintiin eri luokitteluperustein. Luokittelu voi perustua faktoihin (esim. käyttöjärjestelmäversio, datakeskus) tai asiakaskoneelle erikseen määritettyihin arvoihin (esim. asiakas, koneen kriittisyys liiketoiminnan kannalta).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Eyaml:&lt;/strong&gt; Hieran datatiedostossa (yaml) olevan &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-5-hiera-ja-sisallon-kryptaaminen/&#34;&gt;datan kryptaukseen tarkoitettu työkalu&lt;/a&gt;. Tärkeä erityisesti silloin, kun Hieran dataa säilötään organisaation ulkopuolella kuten esimerkiksi &lt;a href=&#34;https://www.puppeteers.fi/lisaa-laskia-tyonkulkuun-osa-3-gitlab-ja-vastaavat/&#34;&gt;GitLabissa&lt;/a&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;R10k:&lt;/strong&gt; työkalu dynaamisten Puppet environmentien hallintaan. Käytännössä r10k luo kustakin &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/&#34;&gt;hallintarepon&lt;/a&gt; haarasta Puppet environmentin. Kukin haara sisältää environmentin vaatimat Puppet-moduulit sekä niiden tarvitsemat parametrit.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Suositellut työnkulut&lt;/strong&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-4-roolit-ja-profiilit/&#34;&gt;Komponenttimoduulien, roolien ja profiilien käyttö&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/&#34;&gt;Hallintarepon&lt;/a&gt; ja &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-2-r10k/&#34;&gt;r10k&lt;/a&gt;:n käyttö&lt;/li&gt;&#xA;&lt;li&gt;Versionhallinnan (Gitin) käyttö on perusoletus&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;</description>
			</item>
			<item>
				<title>Lisää läskiä työnkulkuun, osa 1: Hallintarepo</title>
				<link>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/</link>
				<pubDate>Wed, 31 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/</guid>
				<description>&lt;p&gt;Mikäli muutosten tekeminen Puppet-koodiin ja Hieraan suoraan puppetmasterilla tuntuu liian kevyeltä ja helpolta, voi Puppet-työnkulusta tehdä asteittain vaikeammaksi oman sietokyvyn mukaan lisäämällä palettiin lisää komponentteja. Esimerkiksi ns. &lt;a href=&#34;https://puppet.com/docs/pe/2017.3/code_management/control_repo.html&#34;&gt;control repon&lt;/a&gt; ja &lt;a href=&#34;https://github.com/puppetlabs/r10k&#34;&gt;r10k&lt;/a&gt;:n käyttö &lt;a href=&#34;https://puppet.com/docs/puppet/5.3/environments_about.html&#34;&gt;Puppetin environmentien&lt;/a&gt; ylläpitoon lisää heti useita vaiheita aiemmin yksinkertaiseen työnkulkuun. Toki tällä saavutetaan myös ihan oikeita etuja, joista lisää tuonnempana.&lt;/p&gt;&#xA;&lt;p&gt;Control repo - tästä lähtien osin suomennettuna &amp;ldquo;hallintarepo&amp;rdquo; - on käytännössä Git repository, jonka jokaisesta haarasta (branch) luodaan (tai ainakin voidaan luoda) dynaamisesti Puppet masterille vastaava Puppet-environment. Hallintarepon oletushaaran nimi, &amp;ldquo;production&amp;rdquo;, on tästä syystä sama, kuin Puppet agenttien oletuksena käyttämä environment. Hallintarepon haaroissa on pitkälti sama sisältö kuin tavanomaisessa &lt;em&gt;/etc/puppetlabs/code/environments/production&lt;/em&gt; -kansiossakin olisi:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lisää läskiä työnkulkuun, osa 2: r10k</title>
				<link>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-2-r10k/</link>
				<pubDate>Wed, 31 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-2-r10k/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/&#34;&gt;Edellisessä blogipostauksessa&lt;/a&gt; esiteltiin tyypillinen hallintarepon rakenne. Tässä artikkelissa käsitellään &lt;a href=&#34;https://github.com/puppetlabs/r10k&#34;&gt;r10k&lt;/a&gt;:ta, jolla hallintarepon haaroista muodostetaan Puppet-palvelimelle vastaavat Puppet-environmentit. R10k:n asennus Puppet 4:een tai uudempaan on suoraviivaista Puppet-pakettien mukana tulevalla gem-ohjelmalla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ /opt/puppetlabs/puppet/bin/gem install r10k&#xA; &lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tämän jälkeen luodaan r10k:lle asetustiedosto &lt;em&gt;/etc/puppetlabs/r10k/r10k.yaml:&lt;/em&gt;&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;---&#xA; :cachedir: /opt/puppetlabs/puppet/cache/r10k&#xA; :sources:&#xA; control:&#xA; basedir: /etc/puppetlabs/code/environments&#xA; prefix: false&#xA; remote: git@gitlab.com:myorg/control-repo.git&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Yllä oletetaan, että hallintarepo (&amp;ldquo;control repo&amp;rdquo;) on jo olemassa GitLabissa tai vastaavassa, ja että &lt;a href=&#34;https://docs.gitlab.com/ce/ssh/README.html&#34;&gt;SSH-avaimet&lt;/a&gt; on luotu ja lisätty hallintarepoon sekä mahdollisiin yksityisiin Puppet-moduulirepoihin, joihin Puppetfilessä viitataan.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lisää läskiä työnkulkuun, osa 3: GitLab ja vastaavat</title>
				<link>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-3-gitlab-ja-vastaavat/</link>
				<pubDate>Wed, 31 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-3-gitlab-ja-vastaavat/</guid>
				<description>&lt;p&gt;Edellisissä artikkeleissa käsiteltiin &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/&#34;&gt;hallintarepoa&lt;/a&gt; ja &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-2-r10k/&#34;&gt;r10k&lt;/a&gt;:ta. Vaikka mikään ei estäkään hallintarepon pitämistä Puppetmaster-koneella ja &lt;a href=&#34;https://www.puppeteers.fi/lisaa-laskia-tyonkulkuun-osa-2-r10k/&#34;&gt;r10k.yaml&lt;/a&gt;:n osoittamista siihen, menetettäisiin silloin monta työvaihetta eikä ratkaisu siten sopisi tämän artikkelisarjan teemaan. Viimeinen puuttuva komponentti työnkulun läskiyttämisessä onkin GitLab tai vastaava, kuten GitHub tai Bitbucket. Näistä ensimmäinen soveltuu parhaiten tilanteeseen, jossa halutaan luoda paljon yksityisiä Git-repoja, joista ei haluta maksaa, eikä GitLabin edistyneemmille ominaisuuksille ole käyttöä. GitHubissa jokainen yksityinen repository maksaa, joten se on kallis ratkaisu yksityisten puppet-moduulien säilömiseen. Bitbucket sallii GitLabin tavoin rajoittamattomasti yksityisiä repositoryjä, mutta rajoittaa käyttäjien määrän tällä hetkellä viiteen, eikä tarjoa merkittävästi etuja, paitsi ehkä &lt;a href=&#34;https://blog.bitbucket.org/2017/09/13/say-trello-to-boards-in-bitbucket/&#34;&gt;Trello-integraation&lt;/a&gt;, jos Kanbania haluaa käytellä. GitLabilla on puolellaan vielä se etu, että se on avointa lähdekoodia, joten sen voi asentaa myös omaan sisäverkkoon ja käyttää sieltä.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Lisää läskiä työnkulkuun, osa 4: Roolit ja profiilit</title>
				<link>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-4-roolit-ja-profiilit/</link>
				<pubDate>Wed, 31 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-4-roolit-ja-profiilit/</guid>
				<description>&lt;p&gt;Mikäli &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-1-hallintarepo/&#34;&gt;hallintarepon&lt;/a&gt;, &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-2-r10k/&#34;&gt;r10k:n&lt;/a&gt; ja &lt;a href=&#34;https://www.puppeteers.net/blog/lisaa-laskia-tyonkulkuun-osa-3-gitlab-ja-vastaavat/&#34;&gt;GitLab:in&lt;/a&gt; sisältävä työnkulku tuntuu vielä liian kevyeltä, on läskiä ja abstraktiotasoja lisättävissä onneksi toisaalla, nimittäin itse Puppet-moduuleissa. Pelastuksen tarjoaa ns. &amp;ldquo;Roles and Profiles pattern&amp;rdquo;, jonka &lt;a href=&#34;http://www.craigdunn.org/2012/05/239/&#34;&gt;kehitti alunperin&lt;/a&gt; Craig Dunn, ja joka löi läpi todennäköisesti Gary Larizzan &lt;a href=&#34;http://garylarizza.com/blog/2014/02/17/puppet-workflow-part-2/&#34;&gt;blogikirjoitusten&lt;/a&gt; myötä. Alla käytämme englanninkielisen termin sijaan lähes suomenkielistä termiä &amp;ldquo;roolit ja profiilit&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;Roolit ja profiilit ovat aivan tavallisia Puppet-luokkia. Ne eivät ole kuitenkaan ole &lt;a href=&#34;http://garylarizza.com/blog/2014/02/17/puppet-workflow-part-1/&#34;&gt;Gary Larizzan termiä&lt;/a&gt; käyttäen ns. komponenttimoduuleja, jotka on suunniteltu jonkin yksittäisen asian tekoon, ja jotka olisivat siten (ainakin periaatteessa) jaettavissa muiden käyttäjien kesken esim. Puppet Forgessa.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Windows hallintaan Puppetilla</title>
				<link>https://www.puppeteers.net/blog/windows-hallintaan-puppetilla/</link>
				<pubDate>Tue, 16 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/windows-hallintaan-puppetilla/</guid>
				<description>&lt;p&gt;Puppet on jo pitkään tukenut Windowsia. Monet natiivit Puppet-resurssit, kuten File, Package ja Service ovat jo pitkään toimineet sekä *NIX-käyttöjärjestelmissä että Windowsissa. Lisäksi osa natiiveista Puppet-resursseista, kuten &lt;a href=&#34;https://github.com/puppetlabs/puppetlabs-registry&#34;&gt;Registry&lt;/a&gt; on suunniteltu pelkästään Windows-käyttöön.&lt;/p&gt;&#xA;&lt;p&gt;Puppetin käyttömukavuus Windows-järjestelmien ylläpidossa on parantunut mutkan kautta muutamien uusien teknologioiden myötä:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://docs.microsoft.com/en-us/powershell/dsc/overview&#34;&gt;Powershell DSC&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://chocolatey.org/&#34;&gt;Chocolatey&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://github.com/Puppet-Finland/puppetlabs-powershell&#34;&gt;Powershell Exec provider&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Powershell DSC perustuu resurssien tilan hallintaan, aivan kuten Puppetkin. Mikä parasta, Puppet-koodissa voi käyttää natiivien Puppet-resurssien lisäksi Powershell DSC-resursseja. Puppetlabsin &lt;a href=&#34;https://puppet.com/blog/managing-powershell-dsc-puppet&#34;&gt;blogikirjoitus&lt;/a&gt; on hyvä alustus tähän aiheeseen. DSC vaatii toimiakseen Powershell 5.0:n, joka tulee &lt;a href=&#34;https://www.microsoft.com/en-us/download/details.aspx?id=50395&#34;&gt;Windows Management Framework 5.0:n&lt;/a&gt; mukana.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershell ja Windows hosts-tiedoston muokkaaminen</title>
				<link>https://www.puppeteers.net/blog/powershell-ja-windows-hosts-tiedoston-muokkaaminen/</link>
				<pubDate>Mon, 15 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershell-ja-windows-hosts-tiedoston-muokkaaminen/</guid>
				<description>&lt;p&gt;Windowsissa voidaan käyttää hosts-tiedostoa ip-osoitteiden ja nimien liittämiseen toisiinsa, aivan kuten Linuxissakin. Linuxissa tiedoston sijainti on /etc/hosts, Windowsissa se on c:windowssystem32driversetchosts, tai oikeastaan $env:windirsystem32driversetchosts.&lt;/p&gt;&#xA;&lt;p&gt;Hosts-tiedoston käyttäminen tulee ajankohtaiseksi silloin kun sovellus tarvitsee DNS-nimen, eikä DNS-palvelinta ole käytettävissä, tai sitä ei voida jostakin syystä käyttää.&lt;/p&gt;&#xA;&lt;p&gt;Jos Puppet agentille ei ole määritetty palvelinta, se yrittää oletuksena yhteyttä palvelimeen jonka DNS-nimi on &amp;lsquo;puppet&amp;rsquo;, eli jos palvelimelle on määritetty domain &amp;rsquo;example.com&amp;rsquo;, agent hakee palvelinta jonka DNS-nimi on &amp;lsquo;puppet.example.com&amp;rsquo; Määrittämällä server-asetuksella palvelimen DNS-nimi, voidaan Puppet agent osoittaa haluttuun palvelimeen. Tämä määritetään Linuxeissa tyypillisesti uusimmissa puppet-versioissa tiedostossa /etc/puppetlabs/puppet/puppet.conf osiossa main tai agent.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershell-provisiointiskriptien käyttö Vagrantissa</title>
				<link>https://www.puppeteers.net/blog/powershell-provisiointiskriptien-kaytto-vagrantissa/</link>
				<pubDate>Mon, 15 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershell-provisiointiskriptien-kaytto-vagrantissa/</guid>
				<description>&lt;p&gt;Vagrantin &lt;a href=&#34;https://www.vagrantup.com/docs/provisioning/shell.html&#34;&gt;shell-provisioner&lt;/a&gt; tukee suoraan Powershell-skriptejä. Toisin sanoen Windows-virtuaalikoneen asetuksia voi muokata Powershellillä ilman, että tarvitsee &lt;a href=&#34;https://www.puppeteers.net/blog/vagrant-ja-windows-boxien-rakentaminen/&#34;&gt;rakentaa uusi virtuaalikonekuva&lt;/a&gt;. Tyypillinen esimerkki on Windows liittäminen konfiguraationhallintajärjestelmään kuten Puppetiin.&lt;/p&gt;&#xA;&lt;p&gt;Vagrantin dokumentaatiossa mainitaan, että Powershell-skriptille voi välittää parametreja &lt;em&gt;powershell_args&lt;/em&gt; -valinnalla joko merkkijonona (string) tai listana (array). Esimerkkejä etenkin Powershell-provisioinnista on kuitenkin heikosti, mistä syystä tämäkin blogipostaus on kirjoitettu. Otetaan esimerkkinä skripti &lt;em&gt;bootstrap_windows.ps1&lt;/em&gt;_,_ joka liittää Windows-virtuaalikoneen olemassa olevaan Puppetserveriin. Sitä käytetään käsin Powershellistä seuraavasti:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;gt; .bootstrap_windows.ps1 -certName win2012r2.local&#xA; -ServerName puppet.local&#xA; -puppetServerAddress 192.168.137.10&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Rivinvaihdot on lisätty selvyyden vuoksi.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Vagrant ja Windows-boxien rakentaminen</title>
				<link>https://www.puppeteers.net/blog/vagrant-ja-windows-boxien-rakentaminen/</link>
				<pubDate>Mon, 15 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/vagrant-ja-windows-boxien-rakentaminen/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.vagrantup.com/&#34;&gt;Vagrant&lt;/a&gt; on erittäin kätevä työkalu kehitys- ja testausympäristöjen rakentamiseen. Sillä voidaan helposti ja toistettavasti luoda virtuaalikoneita, joiden asetukset säädetään halutunlaisiksi &lt;a href=&#34;https://www.vagrantup.com/docs/provisioning/&#34;&gt;provisioning-vaiheessa&lt;/a&gt; esimerkiksi &lt;a href=&#34;https://www.vagrantup.com/docs/provisioning/shell.html&#34;&gt;skripteillä&lt;/a&gt; (shell, powershell) tai konfiguraationhallintatyökaluilla kuten &lt;a href=&#34;https://www.vagrantup.com/docs/provisioning/puppet_apply.html&#34;&gt;Puppetilla&lt;/a&gt;. Vagrantin taustalla on yleensä käytössä &lt;a href=&#34;https://www.virtualbox.org/&#34;&gt;Oraclen Virtuabox&lt;/a&gt;, mutta myös muita virtualisointialustoja tuetaan ns. &lt;a href=&#34;https://www.vagrantup.com/docs/providers/&#34;&gt;providerien&lt;/a&gt; avulla.&lt;/p&gt;&#xA;&lt;p&gt;Vagrantilla luodut virtuaalikoneen on myös helppo verkottaa keskenään. Vagrant toimiikin siten hyvin palvelinympäristöjen testauksessa; hyvänä esimerkkinä käy &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-ipa/blob/master/Vagrantfile&#34;&gt;puppet-ipa&lt;/a&gt; -moduuli, jossa Vagrantilla luodaan &lt;a href=&#34;https://www.freeipa.org&#34;&gt;FreeIPA&lt;/a&gt; multi-master -palvelinympäristö sekä useita asiakaskoneita eri käyttöjärjestelmillä. Toinen hyvä esimerkki on &lt;a href=&#34;https://github.com/Puppet-Finland/puppet-bacula/blob/master/Vagrantfile&#34;&gt;puppet-bacula&lt;/a&gt; -moduuli, jossa Vagrantilla luodaan täydellinen &lt;a href=&#34;https://blog.bacula.org/&#34;&gt;Bacula&lt;/a&gt;-varmuuskopiointiympäristö.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Vagrant ja Windows-virtuaalikoneet</title>
				<link>https://www.puppeteers.net/blog/vagrant-ja-windows-virtuaalikoneet/</link>
				<pubDate>Mon, 15 Jan 2018 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/vagrant-ja-windows-virtuaalikoneet/</guid>
				<description>&lt;p&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/vagrant-ja-windows-boxien-rakentaminen/&#34;&gt;Edellisessä artikkelissa&lt;/a&gt; rakennettiin Packerilla ja Boxcutter-templateilla Windows box Vagrant-käyttöön. Tässä artikkelissa näytetään, miten Vagrantilla rakennetaan varsinaisia Windows-virtuaalikoneita.&lt;/p&gt;&#xA;&lt;p&gt;Vagrantia ohjataan &lt;a href=&#34;https://www.vagrantup.com/docs/vagrantfile/&#34;&gt;Vagrantfile&lt;/a&gt;-tiedostolla, joka usein sijaitsee projektin (esim. Puppet-moduuli) päähakemistossa. Jopa hyvin yksinkertainen Vagrantfile riittää Windows-virtuaalikoneen pystyttämiseen:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;# -*- mode: ruby -*-&#xA; # vi: set ft=ruby :&#xA; &#xA; Vagrant.configure(&amp;#34;2&amp;#34;) do |config|&#xA; config.vm.define &amp;#34;win2012r2&amp;#34; do |box|&#xA; box.vm.box = &amp;#34;mwrock/Windows2012R2&amp;#34;&#xA; box.vm.box_version = &amp;#34;0.6.1&amp;#34;&#xA; box.vm.hostname = &amp;#34;windows2012r2a&amp;#34;&#xA; box.vm.network &amp;#34;private_network&amp;#34;, ip: &amp;#34;192.168.31.101&amp;#34;&#xA; box.vm.provider &amp;#34;virtualbox&amp;#34; do |vb|&#xA; # Poistetaan Virtualboxin konsolinäkymä käytöstä&#xA; vb.gui = false&#xA; vb.memory = 2048&#xA; end&#xA; end&#xA; end&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Yllä käytetään &lt;a href=&#34;https://app.vagrantup.com/mwrock/boxes/Windows2012R2&#34;&gt;erästä&lt;/a&gt; julkista Windows 2012r2 boxia. Aivan yhtä hyvin voitaisiin käyttää &lt;a href=&#34;https://www.puppeteers.fi/vagrant-ja-windows-boxien-rakentaminen/&#34;&gt;aiemmassa artikkelissa&lt;/a&gt; Packerilla luotua boxia tähän tapaan:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet-pohjaisten asennusohjelmien luonti Kafolla</title>
				<link>https://www.puppeteers.net/blog/puppet-pohjaisten-asennusohjelmien-luonti-kafolla/</link>
				<pubDate>Wed, 29 Nov 2017 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-pohjaisten-asennusohjelmien-luonti-kafolla/</guid>
				<description>&lt;p&gt;Puppet on erittäin kätevä erityisesti hyvin monimutkaisten järjestelmien rakentamisessa ja ylläpidossa. Sen avulla on helppoa myös häivyttää suuriakin käyttöjärjestelmäeroja yhden luokkarajapinnan taakse. Hyvänä esimerkkinä käyvät Puppet-Finland-projektin &lt;a href=&#34;https://github.com/Puppet-Finland/thunderbird&#34;&gt;thunderbird&lt;/a&gt;- ja &lt;a href=&#34;https://github.com/Puppet-Finland/openvpn&#34;&gt;openvpn&lt;/a&gt;-moduulit, jotka toimivat useilla eri Linux-jakeluilla ja Windowsilla.&lt;/p&gt;&#xA;&lt;p&gt;Yleensä Puppettia varten rakennetaan palvelinympäristö, joka koostuu &lt;a href=&#34;https://github.com/puppetlabs/puppetserver&#34;&gt;puppetserveristä,&lt;/a&gt; yleensä &lt;a href=&#34;https://github.com/puppetlabs/puppetdb&#34;&gt;puppetdb&lt;/a&gt;:stä sekä mahdollisesti myös &lt;a href=&#34;https://github.com/voxpupuli/puppetboard&#34;&gt;puppetboardista&lt;/a&gt; tai &lt;a href=&#34;https://github.com/theforeman/foreman&#34;&gt;foremanista.&lt;/a&gt; Kullekin hallittavalle koneelle asennettu &lt;a href=&#34;https://github.com/puppetlabs/puppet-agent&#34;&gt;puppet-agent&lt;/a&gt; ottaa yhteyden puppetserveriin esim. kerran puolessa tunnissa, päivittää konfiguraationsa vastaamaan puppetserverillä määriteltyä tilaa ja lähettää raportin puppetserverin kautta puppetdb:lle.&lt;/p&gt;&#xA;&lt;p&gt;Puppettia voidaan ajaa myös paikallisesti ilman puppetserveriä käyttämällä &lt;a href=&#34;https://puppet.com/docs/puppet/5.3/services_apply.html&#34;&gt;puppet apply&lt;/a&gt;-komentoa esimerkiksi seuraavasti:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Vagrant, Powershell ja parametrien välittäminen</title>
				<link>https://www.puppeteers.net/blog/vagrant-powershell-ja-parametrit/</link>
				<pubDate>Mon, 13 Nov 2017 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/vagrant-powershell-ja-parametrit/</guid>
				<description>&lt;p&gt;Vagrant on näppärä väline myös Windows-virtuaalikoneiden luontiin esim. Puppet-resurssien testauksessa. Windows-virtuaalikoneille on luontevaa käyttää Powershell-provisiointia, minkä Vagrant tekee melkoisen yksinkertaiseksi. Aika nopeasti ilmenee tarve välittää Powershell-skriptille parametrejä Vagrantin kautta. Tästä on hieman hankalaa löytää esimerkkejä, joten tässä yksi.&lt;/p&gt;&#xA;&lt;p&gt;Oletetaan että meillä on Powershell-skripti nimeltä bootstrap_windows.ps1 Vagrant-projektin alihakemistossa &amp;lsquo;provision&amp;rsquo;. Skripti asentaa ja konfiguroi Puppet-agentin Windows-virtuaalikoneelle. Skriptille pitää välittää kaksi parametria: Puppetserverin FQDN (serverName) ja mukavuusbonuksena virtuaalikoneelle haluttu FQDN (certName). (Käytän itse Vagrantille yaml-muotoista ns. data-driven vagrant-tiedostoa, joten syntaksi on hieman erilainen vakiomuotoiseen Vagrant-tiedostoon verrattuna).&lt;/p&gt;</description>
			</item>
			<item>
				<title>Debian 9 automaattisen asennuksen tekeminen muistitikulta</title>
				<link>https://www.puppeteers.net/blog/debian-9-automaattisen-asennuksen-tekeminen-muistitikulta/</link>
				<pubDate>Thu, 21 Sep 2017 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/debian-9-automaattisen-asennuksen-tekeminen-muistitikulta/</guid>
				<description>&lt;p&gt;Tässä artikkelissa näytetään kaksi tapaa Debianin asentamiseksi muistitikulta. Ensimmäisessä CD/DVD-asennin yksinkertaisesti kopioidaan muistitikulla, jolloin siitä tulee kätevämpi ja nopeampi CD-levyn korvike. Toinen tapa on monimutkaisempi, mutta mahdollistaa asennusten automatisoinnin helposti. Alla oletetaan, että muistitikun laitetiedosto on /dev/sdb ja että komennot ajetaan pääkäyttäjän oikeuksin esim. sudoa käyttämällä.&lt;/p&gt;&#xA;&lt;p&gt;Koska väärän laitetiedoston käyttäminen voi ylikirjoittaa koko järjestelmälevyn, on muistitikun laitetiedosto syytä tarkistaa esimerkiksi &amp;ldquo;dmesg&amp;rdquo;-komennolla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;[79499.127904] usb 2-1.2: new high-speed USB device number 13 using ehci-pci&#xA; [79499.230913] usb 2-1.2: New USB device found, idVendor=0951, idProduct=1607&#xA; [79499.230918] usb 2-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3&#xA; [79499.230920] usb 2-1.2: Product: DataTraveler 2.0&#xA; [79499.230921] usb 2-1.2: Manufacturer: Kingston&#xA; [79499.230923] usb 2-1.2: SerialNumber: 5B840D0001DA&#xA; [79499.231294] usb-storage 2-1.2:1.0: USB Mass Storage device detected&#xA; [79499.231633] scsi16 : usb-storage 2-1.2:1.0&#xA; [79500.230217] scsi 16:0:0:0: Direct-Access Kingston DataTraveler 2.0 PMAP PQ: 0 ANSI: 0 CCS&#xA; [79500.230722] sd 16:0:0:0: Attached scsi generic sg1 type 0&#xA; [79500.460385] sd 16:0:0:0: [sdb] 15646720 512-byte logical blocks: (8.01 GB/7.46 GiB)&#xA; [79500.461321] sd 16:0:0:0: [sdb] Write Protect is off&#xA; [79500.461327] sd 16:0:0:0: [sdb] Mode Sense: 23 00 00 00&#xA; [79500.462022] sd 16:0:0:0: [sdb] No Caching mode page found&#xA; [79500.462028] sd 16:0:0:0: [sdb] Assuming drive cache: write through&#xA; [79500.465797] sdb: sdb1&#xA; [79500.468449] sd 16:0:0:0: [sdb] Attached SCSI removable disk&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Lisäksi on syytä vamistaa, että kyseiseltä muistitikulta on ylipäätään mahdollista bootata käyttöjärjestelmä tai sen asennin; kaikilta ei nimittäin voi.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Debian snapshots</title>
				<link>https://www.puppeteers.net/blog/debian-snapshots/</link>
				<pubDate>Tue, 20 Dec 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/debian-snapshots/</guid>
				<description>&lt;p&gt;Törmäsin eilen varsin hyödylliseen sivustoon nimeltään &lt;a href=&#34;http://snapshot.debian.org/&#34;&gt;snapshot.debian.org&lt;/a&gt;. Sieltä löytyvät kaikki julkaistut Debian-projektin pakettien versiot. Tämä mahdollistaa pakettien päivittämisen sekä vanhempiin että uudempiin versioihin, mistä on hyötyä mm. selvitettäessä onko jonkin ongelman syy ohjelmistovirhe vai konfiguraatiovirhe.&lt;/p&gt;&#xA;&lt;p&gt;Ohjelmistolähteenä snapshots.debian.org ei toimi, toisin kuin esim. &lt;a href=&#34;https://backports.debian.org/&#34;&gt;backports.debian.org&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Sekalaisia komentoja Samban debuggaukseen</title>
				<link>https://www.puppeteers.net/blog/sekalaisia-komentoja-samban-debuggaukseen/</link>
				<pubDate>Tue, 20 Dec 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/sekalaisia-komentoja-samban-debuggaukseen/</guid>
				<description>&lt;p&gt;Alla tukku hyödyllisiä komentoja Samban debuggaukseen. Oletus on, että Samba AD DC ja Domain Member-palvelinten konfiguraatiot ovat pääosin kunnossa. Tähän pisteeseen päästään helpohkosti Puppet-Finland -projektin &lt;a href=&#34;https://github.com/Puppet-Finland/samba4&#34;&gt;samba4-moduulilla&lt;/a&gt;. Täysin hands off -asennus on varsin haastava, joten debuggaustyökaluille tulee väistämättä tarvetta.&lt;/p&gt;&#xA;&lt;p&gt;Tarkistetaan, onko &lt;em&gt;member&lt;/em&gt;-nimisellä koneella jo machine account Samban LDAP:ssa, eli onko se jo liitetty domainiin:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ net ads dn &amp;#39;CN=member,CN=Computers,DC=smb,DC=domain,dc=com&amp;#39; cn -U administrator%password&#xA; Got 1 replies&#xA; &#xA; cn: member&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tässä eräs toinen tapa selvittää, onko member-kone liitetty domainiin. Tähän vaaditaan Debianissa &lt;em&gt;ldb-tools&lt;/em&gt; -paketin asentaminen ja komento on ajettava DC-koneella:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Prosessien tietojen etsiminen Powershellillä</title>
				<link>https://www.puppeteers.net/blog/prosessien-tietojen-etsiminen-powershellilla/</link>
				<pubDate>Wed, 09 Nov 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/prosessien-tietojen-etsiminen-powershellilla/</guid>
				<description>&lt;p&gt;UNIX-tyyppissä järjestelmissä prosessitaulun tarkastelu on helppoa &lt;em&gt;ps&lt;/em&gt;-komennolla. Samainen komento löytyy Powershellistäkin, mutta se on vain alias &lt;em&gt;Get-Process&lt;/em&gt; CmdLetille, jolla saadaan helposti selville, mitä prosesseja järjestelmässä on käynnissä (alla typistetty tuloste):&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;gt; Get-Process&#xA; &#xA; Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName&#xA; ------- ------ ----- ----- ----- ------ -- -----------&#xA; 136 8 6428 8084 569 0.08 916 bash&#xA; 26 3 1496 2272 16 0.02 1560 cmd&#xA; 57 7 1096 5852 57 0.03 2144 firefox&#xA; 0 0 0 4 0 0 openvpn&#xA; 88 7 988 3668 50 0.02 2676 openvpnserv&#xA; 34 3 500 2332 14 0.00 4940 openvpnserv&#xA; 562 27 151992 161440 615 4.27 2388 powershell&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Jos prosessin nimi on jo tiedossa, voidaan se antaa -Name -parametrilla - huomaa, että .exe jätetään pois lopusta:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Cobbler autodetect system name</title>
				<link>https://www.puppeteers.net/blog/cobbler-autodetect-system-name/</link>
				<pubDate>Wed, 05 Oct 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/cobbler-autodetect-system-name/</guid>
				<description>&lt;p&gt;Cobblerissa on eräs varsin heikosti dokumentoitu ominaisuus, jonka avulla on mahdollista selvittää, mikä kyselyn tekevän koneen nimi Cobblerissa on. Tästä on hyötyä esimerkiksi Windowsin bootstrappauksessa, jotta saadaan noudettua oikeaan Cobbler System-olioon liittyvä &lt;em&gt;Unattended.xml&lt;/em&gt; -tiedosto. Linuxien tapauksessa tähän kikkailuun ei ole tarvetta, koska Cobblerin parametrit välittyvät käyttöjärjestelmän asentimelle suoraan kickstart- tai preseed tiedoston mukana.&lt;/p&gt;&#xA;&lt;p&gt;Itse ominaisuus on erittäin yksinkertainen käyttää, kunhan muistaa ajaa sen siltä koneelta, jonka System name halutaan tietää:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Cobbler templatet</title>
				<link>https://www.puppeteers.net/blog/cobbler-templatet/</link>
				<pubDate>Wed, 05 Oct 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/cobbler-templatet/</guid>
				<description>&lt;p&gt;Käytämme työasemien ja osin myös palvelimien provisioinnissa &lt;a href=&#34;https://cobbler.github.io/&#34;&gt;Cobbleria&lt;/a&gt;. Se on vahvimmillaan juuri fyysisten laitteiden provisionnissa, vaikka perustason tuki myös virtuaalikoneiden provisioinnille löytyykin. Cobbler nitoo yhteen lukuisia eri palveluita (dhcp, dns, tftp) Python-koodin avulla, joten aivojen vääntäminen sen vaatimiin asetuksiin vie aikansa. Cobblerin perusdokumentaatio on RedHatille tyypilliseen tyyliin varsin hyvää, mutta ongelmiin joutuu helposti, kun halua tehdä jotain virallisen dokumentaation ulkopuolelta. Esimerkiksi Cobblerin web-API on dokumentoitu varsin heikosti, lähinnä &lt;a href=&#34;https://fedorahosted.org/cobbler/wiki/ModPythonDetails&#34;&gt;tässä Wiki-artikkelissa&lt;/a&gt;. Tässä ja tulevissa blogikirjoituksissa pyritään paikkaamaan Cobblerin dokumentaation puutetta.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hieran debuggauksesta</title>
				<link>https://www.puppeteers.net/blog/hieran-debuggauksesta/</link>
				<pubDate>Wed, 15 Jun 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/hieran-debuggauksesta/</guid>
				<description>&lt;p&gt;Toisinaan Puppet-koodissa on tarve tehdä &lt;a href=&#34;https://docs.puppet.com/hiera/3.1/lookup_types.html&#34;&gt;haku Hierasta&lt;/a&gt;, mutta se ei toimi odotetulla tavalla. Näissä tapauksissa auttaa &amp;ldquo;puppet lookup&amp;rdquo;-komento:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ puppet lookup --node www.domain.com --explain bacula::filedaemon::backup_files&#xA; Data Binding &amp;#34;hiera&amp;#34;&#xA; Found key: &amp;#34;bacula::filedaemon::backup_files&amp;#34; value: [&#xA; &amp;#34;/etc&amp;#34;,&#xA; &amp;#34;/var/lib/puppet/ssl&amp;#34;,&#xA; &amp;#34;/var/backups/local&amp;#34;&#xA; ]&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Erikoista kyllä, tämä komento löytää ainoastaan ne Hieran hierarkian tasot, jotka perustuvat faktoihin:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;---&#xA; :backends:&#xA; - yaml&#xA; :hierarchy:&#xA; - &amp;#34;nodes/%{::trusted.certname}&amp;#34;&#xA; - &amp;#34;roles/%{::role}&amp;#34;&#xA; - &amp;#34;lsbdistcodename/%{::lsbdistcodename}&amp;#34;&#xA; - &amp;#34;osfamily/%{::osfamily}&amp;#34;&#xA; - &amp;#34;kernel/%{::kernel}&amp;#34;&#xA; - common&#xA; &#xA; :yaml:&#xA; :datadir:&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Yllä muuttuja &lt;em&gt;role&lt;/em&gt; ei siis ole fakta, vaan se on oikeastaan parametri tai käytänne, joka määritetään noodin yaml-tiedostossa:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Windowsin järjestelmätiedostojen ylikirjoittaminen Puppetilla</title>
				<link>https://www.puppeteers.net/blog/windowsin-jarjestelmatiedostojen-ylikirjoittaminen-puppetilla/</link>
				<pubDate>Sat, 09 Apr 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/windowsin-jarjestelmatiedostojen-ylikirjoittaminen-puppetilla/</guid>
				<description>&lt;p&gt;Windowsin järjestelmätiedostoja ei useinkaan pysty muuttamaan käsin - tai Puppetilla - ilman niiden suojaustason alentamista. Ongelma on siinä, että järjestelmätiedostojen omistaja on usein (pseudo)käyttäjä &amp;ldquo;TrustedInstaller&amp;rdquo;, eikä edes administrator-tason käyttäjillä ole niihin kirjoitusoikeutta. Onneksi rajoitukset voi kiertää melko suoraviivaisesti käyttämällä &lt;a href=&#34;https://technet.microsoft.com/en-us/library/cc753024.aspx&#34;&gt;takeown.exe&lt;/a&gt; -komentoa sekä &lt;a href=&#34;https://github.com/puppetlabs/puppetlabs-acl&#34;&gt;puppetlabs/acl&lt;/a&gt; -moduulia. Alla on muokattu erästä Group Policyn XML-tiedostoa, jonka merkistökoodaus oli siinä määrin poikkeuksellinen, että sen lukeminen Rubyn reXML -kirjastolla ei onnistunut:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;include ::acl&#xA; &#xA; # Vaihda tiedoston omistaja&#xA; exec { &amp;#39;takeown-Search.admx&amp;#39;:&#xA; command =&amp;gt; &amp;#39;C:WindowsSystem32takeown.exe /f C:WindowsPolicyDefinitionsSearch.admx&amp;#39;,&#xA; }&#xA; &#xA; # Määritä uudet oikeudet&#xA; acl { &amp;#39;Search.admx&amp;#39;:&#xA; target =&amp;gt; &amp;#39;C:/Windows/PolicyDefinitions/Search.admx&amp;#39;,&#xA; permissions =&amp;gt; [&#xA; { identity =&amp;gt; &amp;#39;Järjestelmänvalvojat&amp;#39;, rights =&amp;gt; [&amp;#39;full&amp;#39;] },&#xA; { identity =&amp;gt; &amp;#39;SYSTEM&amp;#39;, rights =&amp;gt; [&amp;#39;full&amp;#39;] }&#xA; ],&#xA; require =&amp;gt; Exec[&amp;#39;takeown-Search.admx&amp;#39;],&#xA; }&#xA; &#xA; # Korvaa tiedosto&#xA; file { &amp;#39;C:/Windows/PolicyDefinitions/Search.admx&amp;#39;:&#xA; source =&amp;gt; &amp;#39;puppet:///modules/winpolicydefinitions/Search.admx&amp;#39;,&#xA; require =&amp;gt; Acl[&amp;#39;Search.admx&amp;#39;], &#xA; }&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tästä prosessista kannattaisi muokata oma määritelty resurssinsa, tai jopa peräti oma tyyppinsä, mikäli sille löytyisi runsaasti käyttöä. Takeown-komentoon kannattaisi lisätä myös &amp;ldquo;unless&amp;rdquo;-parametri, jotta sitä ei ajeta turhaan joka kerta. Jos Execissä olisi &amp;ldquo;provider =&amp;gt; &amp;lsquo;powershell&amp;rsquo;&amp;rdquo;, niin tarkistuksen voisi tehdä &lt;a href=&#34;http://stackoverflow.com/questions/22943289/powershell-what-is-the-best-way-to-check-whether-the-current-user-has-permissio&#34;&gt;muutamin eri tavoin&lt;/a&gt;.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Windowsin paikallisten ryhmäkäytäntöjen muokkaus Puppetilla</title>
				<link>https://www.puppeteers.net/blog/windowsin-paikallisten-ryhmakaytantojen-muokkaus-puppetilla/</link>
				<pubDate>Sat, 09 Apr 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/windowsin-paikallisten-ryhmakaytantojen-muokkaus-puppetilla/</guid>
				<description>&lt;p&gt;Monia Windowsien asetuksia on perinteisesti muokattu ryhmäkäytänteillä (&amp;ldquo;Group Policy&amp;rdquo;). Vaikka ryhmäkäytänteiden teho &lt;a href=&#34;http://www.theregister.co.uk/2010/07/06/sysadmin_using_group_policy/&#34;&gt;onkin melko rajallinen&lt;/a&gt;, pystyy niillä tekemään yhtä ja toista. Microsoft on kuitenkin &lt;a href=&#34;https://msdn.microsoft.com/en-us/PowerShell/dsc/overview&#34;&gt;Powershell DSC:n&lt;/a&gt; kuitenkin siirtymässä tilan hallintaan perustuviin modernimpiin ratkaisuja, joten Group Policyt jäänevät lähivuosina historiaan.&lt;/p&gt;&#xA;&lt;p&gt;Tästä huolimatta ryhmäkäytänteitä hyödynnetään yhä erityisesti Active Directory -toimialueiden (&amp;ldquo;domain&amp;rdquo;) kanssa silloin, kun halutaan standardisoida työasemien asetuksia. Myös Samba 4 tukee ryhmäkäytänteiden jakelua työasemille. Ryhmäkäytänteet eivät kuitenkaan vaadi Active Directoryn tai Samba 4:n käyttöä, sillä käytänteitä voidaan määrittää paitsi verkkoalueelle, myös paikallisesti (&amp;ldquo;Local Group Policy&amp;rdquo;). Käytänteet voidaan lisäksi jakaa käyttäjäkohtaisiin (&amp;ldquo;User policy&amp;rdquo;) ja tietokonekohtaisiin (&amp;ldquo;Machine policy&amp;rdquo;).&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 12</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-12/</link>
				<pubDate>Wed, 06 Apr 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-12/</guid>
				<description>&lt;p&gt;Toisinaan tulee tarpeelliseksi etsiä yhdestä tai useammasta tiedostosta jotakin merkkijonoa ja tulostaa täsmäävä rivi sekä tiedosto, jossa se on, sekä rivinumero. GNU grepillä tämä onnistuu triviaalisti komennolla &amp;ldquo;grep -HN pattern&amp;rdquo;:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ grep -Hn REXML *.rb&#xA; group_policy.rb:71: dFile = REXML::Document.new( File.new(&amp;#34;#{dDir}\#{array[0][0]}.admx&amp;#34;))&#xA; group_policy.rb:72: eFile = REXML::Document.new( File.new(&amp;#34;#{eDir}\#{array[0][0]}.adml&amp;#34;))&#xA; group_policy.rb:154: dFile = REXML::Document.new( File.new(&amp;#34;#{dDir}\#{sys_tShort}.admx&amp;#34;))&#xA; group_policy.rb:155: eFile = REXML::Document.new( File.new(&amp;#34;#{eDir}\#{sys_tShort}.adml&amp;#34;))&#xA; group_policy.rb:428: dFile = REXML::Document.new( File.new(&amp;#34;#{dDir}\#{tShort}.admx&amp;#34;))&#xA; group_policy.rb:429: eFile = REXML::Document.new( File.new(&amp;#34;#{dDir}\#{adml}&amp;#34;))&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Sama homma onnistuu myös Powershellissä, mutta hieman vaikeammin:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 10</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-10/</link>
				<pubDate>Thu, 10 Mar 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-10/</guid>
				<description>&lt;p&gt;Windowsin käynnistyviin ohjelma- ja kirjastotiedostoihin liittyy paljon erilaista metatietoa, esimerkiksi ohjelman versionumero, julkaisija yms. Näiden metatietojen tarkastelu on toisinaan hyödyllistä, etenkin ohjelmistoja testattaessa. Alla OpenVPN:n &lt;em&gt;bin&lt;/em&gt; -kansion sisältö kokonaisuudessaan:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PS C:Program FilesOpenVPNbin&amp;gt; Get-ChildItem &#xA; &#xA; Directory: C:Program FilesOpenVPNbin &#xA; &#xA; Mode LastWriteTime Length Name&#xA; ---- ------------- ------ ----&#xA; -a--- 7.3.2016 16:40 1753440 libeay32.dll &#xA; -a--- 7.3.2016 16:40 226432 liblzo2-2.dll&#xA; -a--- 7.3.2016 16:40 123000 libpkcs11-helper-1.dll &#xA; -a--- 7.3.2016 16:40 465760 openvpn-gui.exe&#xA; -a--- 7.3.2016 16:40 965984 openvpn.exe &#xA; -a--- 7.3.2016 16:40 65888 openvpnserv.exe &#xA; -a--- 7.3.2016 16:40 396640 ssleay32.dll&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Metatiedot on tallennettu tiedosto-objektin VersionInfo-parametriin - alla tarkastellaan &lt;em&gt;openvpn.exe&lt;/em&gt; -tiedoston metatietoja:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 11</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-11/</link>
				<pubDate>Thu, 10 Mar 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-11/</guid>
				<description>&lt;p&gt;Windowsin tuoteavain (&amp;ldquo;Product Key&amp;rdquo;) löytyy esiasennetuissa koneissa usein koneen pohjasta, mutta entäpä jos Windows onkin jälkiasennettu, tai koneen pohjassa oleva tarra ei edustakaan todellisuutta? Jos tällainen kone soseutuu, ei tuoteavainta löydy tietenkään mistään fyysisestä paikasta, ja tuloksena on kone ilman Windowsia; tämä voi toki olla toivottavakin asiaintila, mutta lähdetään siitä oletuksesta, ettei näin ole.&lt;/p&gt;&#xA;&lt;p&gt;Tuoteavain on onneksi tallennettu Windowsin rekisteriin, mistä sen saa otettua talteen &lt;a href=&#34;http://www.howtogeek.com/206329/how-to-find-your-lost-windows-or-office-product-keys/&#34;&gt;useilla eri tavoilla.&lt;/a&gt; Koska tässä blogissa keskitytään automaatioon ja Powershellin, mitkään graafiset kikkareet eivät luonnollisestikaan tule kyseeseen. Onneksi homma hoituu myös alla olevalla Powershell-skriptillä (&lt;a href=&#34;http://powershell.com/cs/blogs/tips/archive/2012/04/30/getting-windows-product-key.aspx&#34;&gt;lähde&lt;/a&gt;):&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 9</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-9/</link>
				<pubDate>Sun, 03 Jan 2016 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-9/</guid>
				<description>&lt;p&gt;Toisinaan on tarpeen lisätä tekstitiedoston loppuun rivejä. UNIX:ssa tämä onnistuu helposti echo-komennolla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ echo matti &amp;gt;&amp;gt; vpn.pass&#xA; $ echo salasana &amp;gt;&amp;gt; vpn.pass&#xA; $ cat vpn.pass&#xA; matti&#xA; salasana&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Sama onnistuu Powershellissä, mutta ei suinkaan Write-Host -komennolla, joka olisi echo-komennon lähin vastine, vaan Add-Content -komennolla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;&amp;gt; Add-Content vpn.pass -Value matti&#xA; &amp;gt; Add-Content vpn.pass -Value salasana&#xA; &amp;gt; Get-Content vpn.pass&#xA; matti&#xA; salasana&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Toinen melko yleinen tarve on tiedostojen lataaminen verkosta suoraan komentoriviltä. UNIX:ssa tämä onnistuu helpoiten wget-komennolla:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 8</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-8/</link>
				<pubDate>Mon, 22 Jun 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-8/</guid>
				<description>&lt;p&gt;Tietyn nimisten tiedostojen (tai tyyppisten) poistaminen hakemistosta on melko suoraviivaista GNU findilla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ls&#xA; README.txt stderr.log stdout.log&#xA; $ find . -maxdepth 1 -type f -name &amp;#34;*.log&amp;#34; -exec rm -f {} +&#xA; $ ls&#xA; README.txt&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Valinta &lt;em&gt;&amp;ldquo;maxdepth 1&amp;rdquo;&lt;/em&gt; estää findia poistamasta tiedostoja mahdollisista alihakemistoista.&lt;/p&gt;&#xA;&lt;p&gt;Toinen vaihtoehto on putkittaa tiedostolistaus xargsille:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ls&#xA; README.txt stderr.log stdout.log&#xA; $ ls *.log|xargs rm -f&#xA; $ ls&#xA; README.txt&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tässä ei kuitenkaan erotella toisistaan tiedostoja ja hakemistoja, joten myös mahdolliset .log -päätteiset hakemistot yrittäisiin poistaa siinä epäonnistuen.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 6</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-6/</link>
				<pubDate>Wed, 17 Jun 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-6/</guid>
				<description>&lt;p&gt;UNIX-tyyppisissä käyttöjärjestelmissä on tulee usein tarve etsiä jostain hakemistosta lähiaikoina (alla minuutin sisällä) muuttuneet tiedostot:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ find /var/log/ -mmin -1&#xA; /var/log/debug&#xA; /var/log/user.log&#xA; /var/log/auth.log&#xA; /var/log/syslog&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Sama onnistuu myös Powershellissä ainakin kahdella tavalla, joista ensimmäinen on toiminnallisesti identtinen yllä olevan komennon kanssa:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PS C:UsersAdministratorDownloads&amp;gt; Get-ChildItem . -Recurse|Where-Object { $_.LastWriteTime -ge $(Get-Date).AddMinutes(-120) }|Select LastWriteTime, Name&#xA; &#xA; LastWriteTime Name &#xA; ------------- ----&#xA; 6/18/2015 install.bat&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Yllä oleva komento käy läpi koko hakemiston rekursiivisesti tarkistaen jokaisen tiedoston kohdalla viimeisimmän kirjoitusajan ja verraten sitä Date-objektiin, jossa nykyisestä kellonajasta on vähennetty 120 minuuttia. Toisin sanoen komento näyttää ne tiedostot tai hakemistot, joita on muokattu viimeisen 120 minuutin sisällä. Selkeyden vuoksi tiedostojen tiedoista näytetään selkeyden vuoksi vain nimi ja kirjoitusaika.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 7</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-7/</link>
				<pubDate>Wed, 17 Jun 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-7/</guid>
				<description>&lt;p&gt;Tulosteiden uudelleenohjaus ja paluuarvojen käsittely toimii lähes samoin *NIX-shelleissä ja Windowsin Powershellissä. Alla tarkistetaan Linuxin systemctl-komennolla olemassa olevan (&amp;ldquo;openvpn&amp;rdquo;) ja olemattoman (&amp;ldquo;fake&amp;rdquo;) palvelun tila, ohjataan sekä tuloste että virhetuloste bittitaivaaseen ja tulostetaan komennon paluuarvo:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ systemctl status openvpn &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&#xA; $ echo $?&#xA; 0&#xA; $ systemctl status fake &amp;gt; /dev/null 2&amp;gt;&amp;amp;1&#xA; $ echo $?&#xA; 3&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Kuten näkyy, paluuarvo on 0 jos palvelu on olemassa ja 3 jos sitä ei löydy.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Useiden resurssien luonti lista-parametrien avulla</title>
				<link>https://www.puppeteers.net/blog/useiden-resurssien-luonti-lista-parametrien-avulla/</link>
				<pubDate>Mon, 15 Jun 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/useiden-resurssien-luonti-lista-parametrien-avulla/</guid>
				<description>&lt;p&gt;Toisinaan tulee tarve luoda useita samankaltaisia resursseja, joissa vain jonkin yksittäisen ominaisuuden arvo muuttuu. Esimerkiksi intranetin webbipalvelimeen voi joutua sallimaan yhteydet palomuurin läpi sekä sisäverkon että VPN:n osoiteavaruudesta. Vaikka Puppet ei suoraan tuekaan iteraatiota, sitä voi emuloida antamalla resurssin nimeksi ($title) listan merkkijonon sijaan.&lt;/p&gt;&#xA;&lt;p&gt;Esimerkiksi Puppet-Finlandin &lt;a href=&#34;https://github.com/Puppet-Finland/webserver&#34; title=&#34;Puppet-Finlandin webserver-moduuli&#34;&gt;webserver-moduulissa&lt;/a&gt; on parametrit &lt;em&gt;$allow_address_ipv4&lt;/em&gt; ja &lt;em&gt;$allow_address_ipv6.&lt;/em&gt; Ne voivat saada arvokseen joko merkkijonon (&lt;em&gt;&amp;lsquo;192.168.55.0/24&amp;rsquo;&lt;/em&gt;) tai listan (&lt;em&gt;[&amp;lsquo;192.168.55.0/24&amp;rsquo;, &amp;lsquo;10.69.0.0/16&amp;rsquo;]&lt;/em&gt;):&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;class webserver::packetfilter&#xA; (&#xA; $allow_address_ipv4,&#xA; $allow_address_ipv6&#xA; &#xA; ) inherits webserver::params&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Kummankin parametrin arvo annetaan &lt;em&gt;::webserver::packetfilter::allow_ip&lt;/em&gt; -resurssin nimeksi (&lt;em&gt;$title&lt;/em&gt;):&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 5</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-5/</link>
				<pubDate>Wed, 13 May 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-5/</guid>
				<description>&lt;p&gt;Windowsissa tekstimuotoisia lokitiedostoja UNIX:in tapaan ole, vaan niitä vastaa EventLog, jonka sisältöä voi tutkia kätevästi PowerShellillä. EventLogin lokit (Logs) voi listata seuraavasti:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;PS C:&amp;gt; Get-EventLog -List &#xA; &#xA; Max(K) Retain OverflowAction Entries Log &#xA; ------ ------ -------------- ------- --- &#xA; 20 480 0 OverwriteAsNeeded 3 787 Application &#xA; 20 480 0 OverwriteAsNeeded 0 HardwareEvents &#xA; 512 7 OverwriteOlder 0 Internet Explorer &#xA; 20 480 0 OverwriteAsNeeded 0 Key Management Service &#xA; 20 480 0 OverwriteAsNeeded 2 606 Security &#xA; 20 480 0 OverwriteAsNeeded 1 684 System &#xA; 15 360 0 OverwriteAsNeeded 4 823 Windows PowerShell &lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Halutun lokin (alla &lt;em&gt;System&lt;/em&gt;) viimeisimmät kirjaukset (alla 10) saa näytettyä &lt;em&gt;-Newest&lt;/em&gt; -vivulla:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Puppet-moduulien laadunvarmistus, osa 1: automaattiset tarkistustyökalut</title>
				<link>https://www.puppeteers.net/blog/puppet-moduulien-laadunvarmistus-osa-1-automaattiset-tarkistustyokalut/</link>
				<pubDate>Mon, 27 Apr 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/puppet-moduulien-laadunvarmistus-osa-1-automaattiset-tarkistustyokalut/</guid>
				<description>&lt;p&gt;Puppet-moduulien laatu pysyy korkeana, kun syntaksi- ja tyylivirheitä päästetä edes versionhallintaan asti. Puppet-koodin syntaksivirheet löytyvät helposti:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ puppet parser validate tiedosto&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;ERB-templateiden virheet saa selvitettyä seuraavalla tavalla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ erb -P -x -T &amp;#39;-&amp;#39; tiedosto|ruby -c&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;JSON-tiedostojen (metadata.json) virheet etsiminen vaatii hieman kikkailua:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ cat tiedosto|json_pp -f json -t null&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tyylivirheitä voi etsiä puppet-lint -työkalulla:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ puppet-lint tiedosto&#xA; $ puppet-lint .&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Puppet-lint tunnistaa myös puppet-koodin, joka on eteenpäin tai taaksepäin epäyhteensopivaa. Onkin hyvin järkevää ajaa puppet-koodi aina puppet-lintin läpi ennen suuria Puppet-ympäristön päivityksiä.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Käyttöjärjestelmäerojen hallinta Puppetissa, osa 1</title>
				<link>https://www.puppeteers.net/blog/kayttojarjestelmaerojen-hallinta-puppetissa-osa-1/</link>
				<pubDate>Sun, 26 Apr 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/kayttojarjestelmaerojen-hallinta-puppetissa-osa-1/</guid>
				<description>&lt;p&gt;Puppet-moduulit on melko helppo rakentaa siten, että ne saa helposti toimimaan eri käyttöjärjestelmissä ja käyttöjärjestelmäversioissa. Alla ovat itse hyväksi toteamani kolme korkea tason tapaa käyttöjärjestelmäerojen hallintaan kevyimmästä raskaimpaan:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Params-luokan käyttö&lt;/li&gt;&#xA;&lt;li&gt;Käyttöjärjestelmäriippuvaisten aliluokkien käyttö&lt;/li&gt;&#xA;&lt;li&gt;Uuden moduulin rakentaminen&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Menetelmillä 1 ja 2 pystyy käytännössä hallitsemaan kaikki Unix-tyyppisten käyttöjärjestelmien väliset erot. Menetelmää 3 ei juuri tarvita, paitsi jos jokin käyttöjärjestelmä (lue: Windows) eroa muista käytössä olevista huomattavan paljon.&lt;/p&gt;&#xA;&lt;p&gt;Pieniin eroihin riittää siis &lt;em&gt;params&lt;/em&gt;-luokan käyttö. Otetaan esimerkiksi vaikkapa Puppet-Finlandin &lt;a href=&#34;https://github.com/Puppet-Finland/ntp&#34; title=&#34;ntp-moduuli&#34;&gt;ntp-moduuli&lt;/a&gt;:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Augeas-resurssien luonnista ja debuggaamisesta</title>
				<link>https://www.puppeteers.net/blog/augeas-resurssien-luonnista-ja-debuggaamisesta/</link>
				<pubDate>Tue, 14 Apr 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/augeas-resurssien-luonnista-ja-debuggaamisesta/</guid>
				<description>&lt;p&gt;NOTE: this article is now also available &lt;a href=&#34;https://www.puppeteers.net/blog/using-augeas-to-manage-resources-in-puppet/&#34;&gt;in English&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Puppetin Augeas-resurssilla voidaan muokata konfiguraatiotiedostojen osia sen sijaan, että hallittaisiin koko tiedostoa esim. templatella tai staattisella tiedostolla. Koko tiedoston hallinta tuottaa yleensä varmemmin ja vähemmällä vaivalla halutun lopputuloksen, mutta erityisesti luettelomaisten konfiguraatiotiedostojen tapauksessa Augeas-resurssi on erittäin käyttökelpoinen. Augeaksen käyttö ei-triviaaleissa tapauksissa on kuitenkin varsin haastavaa, ja usein onkin hyödyllistä rakentaa oikeat komennot käsin &amp;ldquo;augtool&amp;rdquo;-kehotteessa ja vasta sitten muuntaa ne Puppetin Augeas-resurssiksi.&lt;/p&gt;&#xA;&lt;p&gt;Aluksi kannattaa tutkia, mikä Augeaksen näkemys jonkin konfiguraatiotiedoston rakenteesta on (ylimääräisiä rivejä on poistettu):&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 3</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-3/</link>
				<pubDate>Thu, 19 Mar 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-3/</guid>
				<description>&lt;p&gt;Powershelliä konffatessa on tullut taas törmättyä useisiin varsin käyttökelpoisiin komentoihin. Alla ei-kattava lista, sillä lisää on luvassa sopivalla hetkellä.&lt;/p&gt;&#xA;&lt;p&gt;Hakemiston poistaminen rekursiivisesti:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ rm -rf hakemisto&#xA; &amp;gt; Remove-Item -Recurse -Path hakemisto&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tiedoston viimeisten rivien näyttäminen:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ cat tiedosto|tail -n &amp;lt;rivien_määrä&amp;gt;&#xA; &amp;gt; Get-Content tiedosto -Last &amp;lt;rivien_määrä&amp;gt;&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tiedoston ensimmäisten rivien näyttäminen&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ cat tiedosto|head -n &amp;lt;rivien_määrä&amp;gt;&#xA; &amp;gt; Get-Content tiedosto -First &amp;lt;rivien_määrä&amp;gt;&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tiedoston rivien määrän laskeminen:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 4</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-4/</link>
				<pubDate>Thu, 19 Mar 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-4/</guid>
				<description>&lt;p&gt;Lisävinkkejä tuli keksittyä nopeammin kuin alunperin osasin uumoillakaan. Näille on ollut käyttöä jo useaan kertaan.&lt;/p&gt;&#xA;&lt;p&gt;Prosessin ID:n löytäminen:&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ ps aux|grep nimi&#xA; &amp;gt; Get-Process -Name nimi&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Prosessin tappaminen PID:n perusteella&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ kill pid&#xA; &amp;gt; Stop-Process -Id pid&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Prosessin tappaminen nimen perusteella&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ pkill nimi&#xA; &amp;gt; Stop-Process -Name nimi&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;h2 id=&#34;powershelliä-unix-ylläpitäjille--artikkelisarjan-muut-osat&#34;&gt;Powershelliä UNIX-ylläpitäjille -artikkelisarjan muut osat:&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-1/&#34;&gt;Osa 1&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-2/&#34;&gt;Osa 2&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-3/&#34;&gt;Osa 3&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Osa 4&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-5/&#34;&gt;Osa 5&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-6/&#34;&gt;Osa 6&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-7/&#34;&gt;Osa 7&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-8/&#34;&gt;Osa 8&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-9/&#34;&gt;Osa 9&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-10/&#34;&gt;Osa 10&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-11/&#34;&gt;Osa 11&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-12/&#34;&gt;Osa 12&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 2</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-2/</link>
				<pubDate>Mon, 23 Feb 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-2/</guid>
				<description>&lt;p&gt;Alla on varsin hyvä vertailu Bashin ja Powershellin komennoista englanniksi (EDIT: sivu on sittemmin valitettavasti poistunut):&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://cecs.wright.edu/~pmateti/Courses/233/Labs/Scripting/bashVsPowerShellTable.html&#34; title=&#34;BASH and PowerShell Quick Reference&#34;&gt;BASH and PowerShell Quick Reference&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Kuten näkyy, Powershellissä on valmiina melko suuri määrä UNIX-tyyppisiä komentojen aliaksia. Aliakset viittaavat kuitenkin Powershell-komentoihin, joten esimerkiksi niiden valitsimet poikkeavat merkittävästi UNIX-komentojen vastaavista.&lt;/p&gt;&#xA;&lt;h2 id=&#34;powershelliä-unix-ylläpitäjille--artikkelisarjan-muut-osat&#34;&gt;Powershelliä UNIX-ylläpitäjille -artikkelisarjan muut osat:&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-1/&#34;&gt;Osa 1&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Osa 2&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-3/&#34;&gt;Osa 3&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-4/&#34;&gt;Osa 4&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-5/&#34;&gt;Osa 5&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-6/&#34;&gt;Osa 6&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-7/&#34;&gt;Osa 7&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-8/&#34;&gt;Osa 8&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-9/&#34;&gt;Osa 9&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-10/&#34;&gt;Osa 10&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-11/&#34;&gt;Osa 11&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-12/&#34;&gt;Osa 12&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;</description>
			</item>
			<item>
				<title>Powershelliä UNIX-ylläpitäjille, osa 1</title>
				<link>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-1/</link>
				<pubDate>Wed, 18 Feb 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/powershellia-unix-yllapitajille-osa-1/</guid>
				<description>&lt;p&gt;Windows-työasemien ja -palvelinten ylläpidosta voi tehdä huomattavasti tehokkaampaa ja hauskempaa &lt;a href=&#34;http://en.wikipedia.org/wiki/Windows_PowerShell&#34;&gt;Windows Powershellillä&lt;/a&gt;. Aiempaan Windowsin komentoriviin (cmd.exe) verrattuna Powershell on varsin ylivoimainen. Tietyt toimet ovat Powershellissä jopa helpompia kuin Unixin komentorivissä kuten Bashissa.&lt;/p&gt;&#xA;&lt;p&gt;Powershellissä käsitellään tekstirivien tai binääridatan sijaan objekteja. joita voidaan putkittaa komennolta toiselle. Objektien käsittely on usein huomattavasti yksinkertaisempaa kuin tekstin, koska komennoissa voidaan viitata objektien ominaisuuksiin, eikä syötettä tarvitse UNIX:in komentorivien tapaan ensin siistiä ja pilkkoa lukuisilla komennoilla (esim. &lt;em&gt;sed, cut, tr&lt;/em&gt; ja &lt;em&gt;awk&lt;/em&gt;) oleellisen tiedon erottelemiseksi.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Määriteltyjen resurssien luonti suoraan Puppet-luokista</title>
				<link>https://www.puppeteers.net/blog/maariteltyjen-resurssien-luonti-suoraan-puppet-luokista/</link>
				<pubDate>Mon, 02 Feb 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/maariteltyjen-resurssien-luonti-suoraan-puppet-luokista/</guid>
				<description>&lt;p&gt;Jotkin Puppet ENC:t (&lt;a href=&#34;https://docs.puppetlabs.com/guides/external_nodes.html&#34;&gt;External Node Classifier&lt;/a&gt;), hyvänä esimerkkinä &lt;a href=&#34;http://theforeman.org/&#34;&gt;Foreman&lt;/a&gt;, eivät tue määriteltyjen resurssien (&lt;a href=&#34;https://docs.puppetlabs.com/puppet/latest/reference/lang_defined_types.html&#34;&gt;Defined Resource Types&lt;/a&gt;) käyttöä suoraan, vaan kaikki konfiguraatiot pitää sisällyttää &lt;a href=&#34;https://docs.puppetlabs.com/puppet/latest/reference/lang_classes.html&#34;&gt;Puppet-luokkiin&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Myös &lt;a href=&#34;https://docs.puppetlabs.com/hiera/1/index.html&#34;&gt;Hieran&lt;/a&gt; kanssa määritellyt resurssit ovat hieman ongelmallisia, koska ne pitää erikseen luoda create_resources funktiolla. Eräs ratkaisu on määrittää kaikki create_resources -funktiot site.pp-tiedostossa (sovellettu &lt;a href=&#34;http://drewblessing.com/blog/-/blogs/puppet-hiera-implement-defined-resource-types-in-hiera&#34;&gt;täältä&lt;/a&gt;):&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;create_resources(&amp;#39;mysqldump::backup&amp;#39;,hiera(&amp;#39;mysqldump_backups&amp;#39;, {}))&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Tämän lähestymistavan ongelma on se, että uudet määritellyt resurssit pitää muistaa lisätä site.pp-tiedostoon.&lt;/p&gt;&#xA;&lt;p&gt;Yksinkertaisempi ja myös Foremanin kanssa toimiva ratkaisu on luoda määritellyt resurssit suoraan Puppet-moduulin pääluokasta (sovellettu &lt;a href=&#34;https://github.com/arnoudj/puppet-sudo&#34;&gt;täältä&lt;/a&gt;):&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hakemistorakenteen luonti rekursiivisesti Puppetilla</title>
				<link>https://www.puppeteers.net/blog/testi/</link>
				<pubDate>Tue, 20 Jan 2015 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/blog/testi/</guid>
				<description>&lt;p&gt;Puppetin File-resurssilla hallitaan tyypillisesti yksittäisiä tiedostoja, hakemistoja tai linkkejä. Tämä on ongelmallista, jos hallittava tiedosto on syvän hakemistorakenteen alla, eikä hakemistorakennetta ole luotu esimerkiksi ohjelman asennuksen yhteydessä. File-resurssi osaa kuitenkin luoda useita tiedostoja, kun sen otsakkeelle ($title) annetaan merkkijonon sijaan lista-tyyppinen muuttuja. Alla esimerkki bind-moduulista&lt;/p&gt;&#xA;&lt;div class=&#34;code-block&#34;&gt;&#xA;    &lt;button class=&#34;code-copy&#34; type=&#34;button&#34; hidden aria-label=&#34;Copy code to clipboard&#34;&gt;&#xA;      &lt;span class=&#34;code-copy-label&#34; aria-hidden=&#34;true&#34;&gt;Copy&lt;/span&gt;&#xA;    &lt;/button&gt;&#xA;    &lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;file { [ &amp;#39;/var/named/chroot&amp;#39;,&#xA; &amp;#39;/var/named/chroot/var&amp;#39;,&#xA; &amp;#39;/var/named/chroot/var/named&amp;#39;,&#xA; &amp;#39;/var/named/chroot/Var/named/data&amp;#39; ]:&#xA; ensure =&amp;gt; directory,&#xA; owner =&amp;gt; root,&#xA; group =&amp;gt; &amp;#34;${::os::params::admingroup}&amp;#34;,&#xA; mode =&amp;gt; 755,&#xA; require =&amp;gt; Class[&amp;#39;bind::install&amp;#39;],&#xA; }&lt;/code&gt;&lt;/pre&gt;&#xA;  &lt;/div&gt;&lt;p&gt;Bindin zone-tiedostoja ei voi asentaa, ennen kuin hakemisto &lt;em&gt;/var/named/chroot/var/named/data&lt;/em&gt; on olemassa. Siis zone-tiedostoon pitää lisätä riippuvuus (Require) yllä olevan luettelon viimeiseen tiedostoon:&lt;/p&gt;</description>
			</item>
			<item>
				<title>Company information</title>
				<link>https://www.puppeteers.net/info/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/info/</guid>
				<description>Information about Puppeteers</description>
			</item>
			<item>
				<title>Privacy policy</title>
				<link>https://www.puppeteers.net/privacy-policy/</link>
				<pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
				<guid>https://www.puppeteers.net/privacy-policy/</guid>
				<description>Privacy policy for Puppeteers</description>
			</item>
	</channel>
</rss>
