<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>HomeOps</title>
        <description>HomeOps is a collection of Tutorials and how tos by and for DevOps and SREs building home lab deployments</description>
        <link>http://www.homeops.tech/</link>
        <atom:link href="http://www.homeops.tech/feed.xml" rel="self" type="application/rss+xml"/>
        <pubDate>Wed, 16 Mar 2022 19:45:25 +0000</pubDate>
        <lastBuildDate>Wed, 16 Mar 2022 19:45:25 +0000</lastBuildDate>
        <generator>Jekyll v3.9.0</generator>
        
            <item>
                <title>Sync Unifi with Hiera</title>
                <description>&lt;p&gt;In my previous &lt;a href=&quot;http://www.homeops.tech/2020/07/15/DHCP-With-Puppet/&quot;&gt;post&lt;/a&gt; I walked you through configuring DHCP with hiera yaml files. These entries allow you to reserve IPs for nodes. These IPs can then also be tied to DNS entries. However I always strive to integrate all services I run. One of those core services is a &lt;a href=&quot;https://evanmccann.net/blog/unifi-ecosystem-overview&quot;&gt;Unifi Controller&lt;/a&gt;. Unifi’s web interface is great for viewing current Wifi clients and also to troubleshoot and track down connectivity issues. However when a system doesn’t
advertise its name, you are presented with a MAC address or in the case of some IOT devices a random string. Vendor lookups don’t always help given the same chipset being used on multiple platforms. In this post I’ll show you how to sync Unifi with a yaml file.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;ruby&lt;/td&gt;
            &lt;td&gt;2.7.0p0&lt;/td&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Unifi&lt;/td&gt;
            &lt;td&gt;5.6.40&lt;/td&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;I have some older Unifi hardware mixed in with newer. This older version supports both.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/mongo-docker.png&quot; alt=&quot;Mongo In Docker&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I run my unifi controller on my synology. I split the controller (Web interface) and its database into separate containers. This is useful for upgrades and migrating the container to different hosts and platforms over time. This also makes it easier for me to connect to the mongo api and rewrite aliases that unifi uses. Lets look at an example of blank node.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/unifi-mac.png&quot; alt=&quot;Unifi Blank&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This node doesn’t add its hostname to DHCP however I know what it is when looking though my DHCP reseverations. It is the dog treat dispenser that doubles as one of the security cameras for the Synology.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;na&quot;&gt;furbo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;mac&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;38:a2:8c:xx:xx:xx'&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.53.167'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The DHCP reservation is working due to the puppet code, but the synology is unable to lookup this data on its own. While its possible to import this via CSVs I want this to happen automatically do this as I add new nodes. To do this first I write a script that will read a yaml file on disk and update the names based on the format above.&lt;/p&gt;

&lt;h1&gt;Push aliases to Unifi&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sync_unif_names.rb&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'mongo'&lt;/span&gt;
 &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'yaml'&lt;/span&gt;

 &lt;span class=&quot;k&quot;&gt;begin&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;dhcp_hosts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;YAML&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/etc/dhcp.yaml'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dhcp_hosts'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dhcp_hosts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;mac_to_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;dhcp_hosts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
     &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Processing &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
     &lt;span class=&quot;n&quot;&gt;mac_to_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'mac'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;downcase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mongo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Client&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'synology.homeops.tech:27117'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:database&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ace'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;collections&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'user'&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'mac'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mac_to_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'mac'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;downcase&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Found: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mac_to_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'mac'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
             &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'hostname'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'hostname'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
             &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'oui'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'oui'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;
             &lt;span class=&quot;n&quot;&gt;collection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_one&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;_id: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'_id'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$set'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mac_to_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;doc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'mac'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}})&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;StandardError&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Error: '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
   &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I can copy my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dhcp.yaml&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc&lt;/code&gt; and run the script and it will sync the names.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/unifi-name.png&quot; alt=&quot;Unifi Name&quot; /&gt;&lt;/p&gt;

&lt;h1&gt;Automating the Sync&lt;/h1&gt;

&lt;p&gt;While its nice to be able to update the Unifi interface en masse, Ideally we should be able to this automatically as the YAML file in hiera is updated.
We can do that with an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;refresh&lt;/code&gt; in Puppet. On the DHCP server (or any node) we apply the following code.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'mongo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'gem'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/usr/local/bin/sync_names.rb'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;owner&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'root'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;mode&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'0700'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'puppet:///modules/profile/sync_names.rb'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;kp&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'monogo'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;nv&quot;&gt;$hosts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dhcp_hosts'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/etc/dhcp.yaml'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;owner&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'root'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;mode&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'0700'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inline_template&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&amp;lt;%= @{ dhcp_hosts: hosts }.to_yaml %&amp;gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
     &lt;span class=&quot;kp&quot;&gt;notify&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/usr/local/bin/sync_names.rb'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

   &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/usr/local/bin/sync_names.rb'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;refreshonly&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$::path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now when I add a new node to my DHCP server, the same puppet run will trigger the script to run. This happens because the local YAML file’s content will change and puppet will issue a refresh notification to the exec.&lt;/p&gt;
</description>
                <pubDate>Thu, 03 Dec 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/12/03/Sync-Unifi-Names/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/12/03/Sync-Unifi-Names/</guid>
                
                <category>uniFi</category>
                
                <category>ubiquiti</category>
                
                <category>wifi</category>
                
                <category>monogodb</category>
                
                <category>synology</category>
                
                <category>puppet</category>
                
                <category>hiera</category>
                
                <category>docker</category>
                
                
            </item>
        
            <item>
                <title>Using Terraform with Proxmox</title>
                <description>&lt;p&gt;In my previous post on using &lt;a href=&quot;http://www.homeops.tech/2020/07/15/Razor-and-Cloud-Init/&quot;&gt;Razor with Cloud Init&lt;/a&gt; I was able to get newly created VMs to PXE boot to razor and automatically install debian. This allows me to quickly deploy VMs for testing and hosting services. However to create these VMs still required clicking though multiple pages of settings in the Proxmox UI. Given I use terraform so much as work I wanted to use it in my home lab. I this quick post I will show you some example
code to provision a VM in proxmox with terraform. New to Terraform, checkout &lt;a href=&quot;https://learn.hashicorp.com/terraform&quot;&gt;Learn&lt;/a&gt;.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;terraform&lt;/td&gt;
            &lt;td&gt;v0.14.5&lt;/td&gt;
            &lt;td&gt;Ubuntu&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Ubuntu&lt;/td&gt;
            &lt;td&gt;20.04&lt;/td&gt;
            &lt;td&gt;Ubuntu&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;One great things about the terraform ecosystem is like other tools such as Puppet it has a  &lt;a href=&quot;https://github.com/Telmate/terraform-provider-proxmox&quot;&gt;provider&lt;/a&gt; architecture. This plugin system allows users to add resources to terraform that can then be use along side built-in ones. You could for instance use terraform to spin up a vault node and then use the vault node to provision the configuration. The same could happen with the Gitlab provider.&lt;/p&gt;

&lt;h1&gt;Installing the Provider&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;versions.tf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-hcl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nx&quot;&gt;terraform&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;required_providers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;proxmox&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;nx&quot;&gt;source&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Telmate/proxmox&quot;&lt;/span&gt;
       &lt;span class=&quot;nx&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2.6.7&quot;&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In the most recent version of terraform you specify the provider version by convention in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;versions.tf&lt;/code&gt; file.
This is akin to something like a Puppetfile or a Git Submodule. It allows you to pin a version of this provider so that you and your team don’t have compatibility issues across invocations.&lt;/p&gt;

&lt;h1&gt;Provisioning a Bare Metal Node&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main.tf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-hcl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;resource&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;proxmox_vm_qemu&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;metrics&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;metrics&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Graphite, Grafana and Collectd&quot;&lt;/span&gt;
 
   &lt;span class=&quot;nx&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;model&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;virtio&quot;&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;bridge&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;vmbr0&quot;&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;firewall&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;nx&quot;&gt;onboot&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
 
   &lt;span class=&quot;nx&quot;&gt;os_type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;cloud-init&quot;&lt;/span&gt;
 
   &lt;span class=&quot;nx&quot;&gt;target_node&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;proxmox&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;boot&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;order=net0;scsi0&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;iso&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;none&quot;&lt;/span&gt;
 
   &lt;span class=&quot;nx&quot;&gt;cores&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;sockets&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;vcpus&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;0&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;cpu&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;host&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;memory&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2048&quot;&lt;/span&gt;
   &lt;span class=&quot;nx&quot;&gt;scsihw&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;virtio-scsi-pci&quot;&lt;/span&gt;
 
 
   &lt;span class=&quot;nx&quot;&gt;disk&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;scsi&quot;&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;64G&quot;&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;format&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;qcow2&quot;&lt;/span&gt;
     &lt;span class=&quot;nx&quot;&gt;storage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mute&quot;&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is an example of Provisioning the Graphana node covered in this &lt;a href=&quot;http://www.homeops.tech/2020/05/20/Graphite-And-Grafana-With-Puppet/&quot;&gt;previous post&lt;/a&gt;. Lets break down some of the important bits here.&lt;/p&gt;

&lt;div class=&quot;language-hcl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;boot&lt;/span&gt;        &lt;span class=&quot;err&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;order=net0;scsi0&quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As I mentioned in the &lt;a href=&quot;http://www.homeops.tech/2020/07/15/Razor-and-Cloud-Init/&quot;&gt;Razor with Cloud Init&lt;/a&gt; ,razor server normally expects network booting to always happen. That includes after a node has been provisioned. This allows razor to centrally reinstall the node.&lt;/p&gt;

&lt;div class=&quot;language-hcl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;disk&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;scsi&quot;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;64G&quot;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;format&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;qcow2&quot;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;storage&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;mute&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This configures the virtual scsi interface that will correspond to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/sda&lt;/code&gt; entry in your preseed.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;At the time of this writing the format ends up being raw instead of qcow.  &lt;a href=&quot;https://github.com/Telmate/terraform-provider-proxmox/issues/291&quot;&gt;Known Bug&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you wanted to simply boot from an iso here you would add:&lt;/p&gt;

&lt;div class=&quot;language-hcl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;boot&lt;/span&gt;        &lt;span class=&quot;err&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;legacy=ncd&quot;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;iso&lt;/span&gt;         &lt;span class=&quot;err&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;synology:iso/debian-10.7.0-amd64-netinst.iso&quot;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is an exmample of an iso placed in the templates directory of the proxmox share.&lt;/p&gt;

&lt;h1&gt;Cloud-init&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
os_type = &quot;cloud-init&quot;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We specify cloud-init here as in the razor example we are not creating this system from a packer image. However that is possible to do with templates in proxmox.&lt;/p&gt;

&lt;p&gt;Ideally we would be able to add the following cloud-init config information&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     sshkeys = &amp;lt;&amp;lt;EOF
       ssh-rsa AAAA...
   EOF

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;However the provider has a heavy handed error message that you cant use cloud-init without templates. Once this is resolved we should be able to use this as a cloud-drive to have proxmox merge configurations with our Razor Cloud Init configuration. This is the &lt;a href=&quot;https://github.com/Telmate/terraform-provider-proxmox/issues/274&quot;&gt;bug&lt;/a&gt; that covers that issue. I might expierement with forking the provider to get it working in the mean time.&lt;/p&gt;

&lt;p&gt;As a side note, this should eventually allow us to tie into Terrform’s  ability to generate cloud-init multi part files.&lt;/p&gt;

&lt;div class=&quot;language-hcl highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;nx&quot;&gt;Source&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Cloud&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Init&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Config&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;template&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;${path.module}/templates/cloud.cfg&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;vars&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;ssh_key&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/home/acidprime/.ssh/id_rsa.pub&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;domain&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;homeops.tech&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;cloudinit_config&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;homeops&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;base64_encode&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;text/x-shellscript&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;baz&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;init.sh&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Main cloud-config configuration file.&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;filename&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;init.cfg&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;content_type&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;text/cloud-config&quot;&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;${data.template_file.script.rendered}&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I will update this post once that bug is updated.&lt;/p&gt;
</description>
                <pubDate>Fri, 16 Oct 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/10/16/Using-Terraform-With-Proxmox/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/10/16/Using-Terraform-With-Proxmox/</guid>
                
                <category>terraform</category>
                
                <category>proxmox</category>
                
                <category>cloud-init</category>
                
                
            </item>
        
            <item>
                <title>Using Synology as a ZeroTier Bridge</title>
                <description>&lt;p&gt;I was introduced to &lt;a href=&quot;https://www.zerotier.com/&quot;&gt;Zero tier&lt;/a&gt; a few years ago. I find it pretty solid and the free plan works well as a sort of reverse NAT style VPN’esk solution.  Each node gets a multi homed IP that’s always available. This means I can ssh into my laptop no matter where it is, or have it backup to an internal server consistently. You don’t have to open any ports up as your routing traffic through their servers. Additionally you don’t need a static IP to make this work.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;DSM&lt;/td&gt;
            &lt;td&gt;DSM 6.2.2-24922 Update 6&lt;/td&gt;
            &lt;td&gt;Synology&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;You need at least one node that’s consistently online to route the traffic from Zero Tier to your devices. You can buy stand alone units for this but I often use my Synology for central services like this. To get started you will need the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/zerodownload.png&quot; alt=&quot;ZeroDownload&quot; /&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Sign up for account: &lt;a href=&quot;https://my.zerotier.com/&quot;&gt;https://my.zerotier.com/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Download correct Synology Package for your arch &lt;a href=&quot;https://download.zerotier.com/dist/synology/&quot;&gt;https://download.zerotier.com/dist/synology/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Use the &lt;a href=&quot;https://github.com/SynoCommunity/spksrc/wiki/Architecture-per-Synology-model&quot;&gt;Github Wiki&lt;/a&gt; to find the right arch&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Install Package&lt;/h1&gt;

&lt;p&gt;Using the Package Center add the package via the Manual Install Button&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/zerominstall.png&quot; alt=&quot;ManualInstall&quot; /&gt;&lt;/p&gt;

&lt;h1&gt;Join the Zero Tier network&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/zeroconfig.png&quot; alt=&quot;ZerConfig&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Grab your network ID from &lt;a href=&quot;https://my.zerotier.com/&quot;&gt;https://my.zerotier.com/&lt;/a&gt; and launch the Zero Tier app you installed via Package Center.&lt;/p&gt;

&lt;h1&gt;Enable Routing &amp;amp; Nat&lt;/h1&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/sysctl.conf&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;net.ipv4.conf.all.forwarding&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
net.ipv4.conf.default.forwarding&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
net.ipv6.conf.all.forwarding&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
net.ipv6.conf.default.forwarding&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ssh into your Synology and edit the sysctl configuration. Then apply your changes&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sysctl &lt;span class=&quot;nt&quot;&gt;--system&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;This needs to be automated but I haven’t decided from a gem installed puppet or hacked ansible for managing my synology yet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Enable IP Tables Rules&lt;/h1&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sudo -s
/sbin/iptables -t nat -A POSTROUTING -o bond0 -j MASQUERADE
/sbin/iptables -A FORWARD -i bond0 -o eth50 -m state --state RELATED,ESTABLISHED -j ACCEPT
/sbin/iptables -A FORWARD -i eth50 -o bond0 -j ACCEPT
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Where is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bond0&lt;/code&gt; is your LAN interface and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eth50&lt;/code&gt; is your zerotier interface&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I have a bond as I use LACP to bond my 4 Ethernet ports together on my DS1515+&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Persistance&lt;/h1&gt;

&lt;p&gt;These need to be set at reboot to stay persistent so you should add them to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/rc.local&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;Configure Bridging&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/zerotier.png&quot; alt=&quot;ZeroTier&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Add your synology to your network and Allow Ethernet bridging. Create a managed route as shown above.&lt;/p&gt;

&lt;h1&gt;Zero Tier on Phone&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/zerophonejoin.png&quot; alt=&quot;PhoneInstall&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now that you have an ethernet bridge you can install the Zero Tier app on your phone and join the network.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/carremote.png&quot; alt=&quot;CarRemote&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see I can connect to my arduino project that allows me to lock my car doors at night.&lt;/p&gt;

&lt;p&gt;If you followed my &lt;a href=&quot;http://127.0.0.1:4000/2020/06/06/DNS-With-Puppet/&quot;&gt;DNS Post&lt;/a&gt; then you can actually use split DNS here as well by allowing this subnet to make calls to your named service.&lt;/p&gt;
</description>
                <pubDate>Wed, 15 Jul 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/07/15/Zero-Tier-On-Synology/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/07/15/Zero-Tier-On-Synology/</guid>
                
                <category>synology</category>
                
                <category>zero tier</category>
                
                <category>dsm</category>
                
                <category>network</category>
                
                
            </item>
        
            <item>
                <title>Using Razor Server with Cloud-Init</title>
                <description>&lt;p&gt;Bare metal imaging is certainly not the rage anymore. Tools like packer allow us to walk the line between golden images and infrastructure as code. I really like packer but I often want more tools in my belt. In a home lab I want to be able to install physical machines with ease the way I install virtual ones at work. Looking at the commit history of razor you can see that its not something being actively updated that much anymore. That said, its actually very versatile software when you get know it. Its light weight and adding
modern tools to the mix makes it work quite well. Its lack of use can also be attributed to it being difficult to get started with. Hopefully this post can help.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;puppet&lt;/td&gt;
            &lt;td&gt;6.21.0&lt;/td&gt;
            &lt;td&gt;centos&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;centos&lt;/td&gt;
            &lt;td&gt;7.9.2009&lt;/td&gt;
            &lt;td&gt;centos&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;I install razor side by side my Puppet server which is on the Centos Box&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Puppetfile&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/acidprime/puppet-razor.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'master'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'wget'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/voxpupuli/puppet-wget.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v2.0.1'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'java'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/puppetlabs/puppetlabs-java.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v6.5.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'postgresql'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/puppetlabs/puppetlabs-postgresql.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v6.5.0'&lt;/span&gt;
 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1&gt;Installing Razor Server&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;k&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;java&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'postgresql::server'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ip_mask_allow_all_users&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'0.0.0.0/0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;postgres_password&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'wget'&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;postgresql::server::db&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;user&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;password&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;postgresql_password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'secret'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/etc/razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;owner&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'directory'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/opt/razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;owner&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'directory'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/var/lib/razor/repo-store'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'directory'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;owner&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/etc/puppetlabs/razor-server/config.yaml'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'link'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/etc/razor/config.yaml'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'razor'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;database_hostname&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'127.0.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;compile_microkernel&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;database_password&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'secret'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;enable_tftp&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I chose razor server, because its actually light weight. Systems like foreman want to take over multiple parts of your infrastructure for their narrative to work. In my case I had two main goals.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;PXE boot new VMs in proxmox&lt;/li&gt;
  &lt;li&gt;PXE boot my Intel NUC&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Its very possible you have never heard of razor before. The basic concept is very intuitive once you start using it. Once you have a razor server, the PXE booted server first boots into an intermediary “micro” kernel which is essentially a tiny Centos7 box. This micro kernel, reports back on the various details of the machine its booted from. These “facts” are collected using Puppet’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;facter&lt;/code&gt; tool. The razor server then can set the next boot to be one of installation or pass through. In other
words on say my Intel NUC I configure to always network boot. This allows razor to check if the box should be installed or perhaps reinstalled. Razor even has IPMI support for proper server hardware to reboot a new box.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I tried to get the IPMI libvirt tools to work with Proxmox only to find that proxmox doesnt support them. Not a huge deal in my case as I often can reboot a node easily.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To reinstall a node type&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;razor reinstall-node node30

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In my previous post I walked you through installing ISC-DHCPD. Those DHCP/DNS/TFTP servers allow me to PXE boot machines in my network with razor. This exposes the Web URLs that razor uses to advance the node on to the next step in the process of being installed.&lt;/p&gt;

&lt;h1&gt;Node Protection&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;razor::razor_yaml_setting&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;all/checkin_interval&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;15&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;razor::razor_yaml_setting&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;all/protect_new_nodes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By default Razor protects new nodes (as to not erase them!). I actually don’t want that protection here as I want to be able to spin a new node up with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform&lt;/code&gt;. I’m also setting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkin&lt;/code&gt; interval here as its required in the template.&lt;/p&gt;

&lt;h1&gt;Razor Repo&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;n&quot;&gt;razor_repo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'debian-buster-amd64-netboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;iso_url&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://deb.debian.org/debian/dists/buster/main/installer-amd64/current/images/netboot/mini.iso&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;task&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'debian'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this example we configure a repo for the debian netboot mini iso. One of the first things I found confusing about razor was new terms it uses for common imaging steps. Some like repo more or less make sense over time.&lt;/p&gt;

&lt;h1&gt;Razor Tags&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;n&quot;&gt;razor_tag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'virtual'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;rule&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'='&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'fact'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'is_virtual'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;razor_tag&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'proxmox'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;rule&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'='&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'fact'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'macaddress'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;54:b2:03:1c:0c:bd&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A tag in razor is a rule set that will be applied to a node. In these examples I am creating a tag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;virtual&lt;/code&gt; that will be applied many times to all virtual nodes. I’m also creating a tag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxmox&lt;/code&gt; that will likely only ever be applied once. This tag is matched only by the mac address. However I can modify it to match multiple mac addresses if I want to install multiple servers.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is sort of the tribble style of deployment as my razor server runs on a proxmox node which in turn can create other proxmox nodes in the cluster.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Razor Broker&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;   &lt;span class=&quot;n&quot;&gt;razor_broker&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cloud-init'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;broker_type&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cloud-init'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'cloud-init'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;razor::broker&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'cloud-init'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'profile'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/puppetlabs/server/apps/razor-server/share/razor-server/brokers'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A razor broker is essentially a script that runs after first boot. While in ye’olden times that was likely &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rc.local&lt;/code&gt;, since systemd we would customize our own script. In my case while I am not adverse to maintaining custom scripts, I wanted to use common tools I use in my day job. Cloud-init is the defacto standard for this sort of first boot config. It even supports puppet’s advanced install features.&lt;/p&gt;

&lt;p&gt;The code above references a custom broker (see below). Lets break it down.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;py&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'cloud-init'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This line allows us to load out cloud-cfg which is the configuration cloud-init uses to configure its’ self on first boot, from hiera. This is nice as most examples on the internet are going to copy and paste-able. Albeit with a little more indentation given its nested under the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cloud-init&lt;/code&gt; key. We don’t get many of the other benefits of hiera here as its ability to merge data is not relevant for this use case. That’s because this hiera call is evaluated in the context of the razor-server and not he respective node. That shouldn’t really be an issue given cloud-init itself can pull in multiple sources of data from multiple types of input.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;razor::broker&lt;/code&gt; is copying our custom broker from our module, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile&lt;/code&gt; to its final location on the razor server. Before we disect that broker (below) lets tie everything together.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Tiny bit hand wavey here as the puppet config needs to be per node, but I do that based on the certname rather then the csr attributes currently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Razor Policies&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;razor_policy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'install_debian_on_virtual'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;repo&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'debian-buster-amd64-netboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;task&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'buster'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;broker&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cloud-init'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;hostname&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'node${id}.homeops.tech'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;root_password&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pveroot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;max_count&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;node_metadata&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;os_version&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;buster&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;tags&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'virtual'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
 
   &lt;span class=&quot;n&quot;&gt;razor_policy&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'proxmox_install'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;repo&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'debian-buster-amd64-netboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;task&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'buster'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;broker&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cloud-init'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;hostname&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'proxmox.homeops.tech'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;root_password&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pveroot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;max_count&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;node_metadata&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;os_version&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;buster&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
     &lt;span class=&quot;py&quot;&gt;tags&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'proxmox'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once you understand the individual building blocks of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tags&lt;/code&gt;,&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;repo&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;broker&lt;/code&gt; a policy should help solidify how they fit together. Simply put a policy is the only actionable item of the lot. Its code references the tag to line up the matching node with the correct repo and broker.&lt;/p&gt;

&lt;p&gt;In the examples above, we are using our two tags to create one dynamic policy and one static policy. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;install_debian_on_virtual&lt;/code&gt; will run 100 times on as many VMs as we throw at it. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxmox_install&lt;/code&gt; will run once. The hostnames on the virtual machines will be dynamic with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${id}&lt;/code&gt; being interpolated into the current node number. The proxmox hostname is static.&lt;/p&gt;

&lt;p&gt;And with that we can now boot any new VM in proxmox right to the install screen. Further when I start my Intel NUC up it does the same. Wait for it…&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/pxe.gif&quot; alt=&quot;PXE&quot; /&gt;&lt;/p&gt;

&lt;h1&gt;Cloud-init Broker.&lt;/h1&gt;

&lt;p&gt;While its not required to use cloud-init, you might be surprised how under utilized the tool normally is. I use puppet to configure my machines and generally that means I want to keep any initial configuration minimum. However be careful to use the right tools at the right time. Puppet when it works, is great but what happens if you are troubleshooting puppet itself. Having a barebones base configuration with cloud-init sounds like a great plan. Given both puppet and the cloud-init broker can read from hiera, you don’t even in practice have to worry about duplication.&lt;/p&gt;

&lt;p&gt;So here is what a bare bones cloud-init configuration can look like&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;c1&quot;&gt;#cloud-config&lt;/span&gt;
 &lt;span class=&quot;na&quot;&gt;cloud-init&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# Initial User Configuration&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;homeops&lt;/span&gt; 
 
   &lt;span class=&quot;na&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;default&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;homeops&lt;/span&gt; 
       &lt;span class=&quot;na&quot;&gt;gecos&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;homeops.tech&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;shell&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/bin/bash&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;primary_group&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;homeops&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;sudo&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ALL=(ALL) NOPASSWD:ALL&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;users, admin&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;lock_passwd&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;ssh_authorized_keys&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
         &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssh-rsa AAAAB3Nz...&lt;/span&gt;
 
   &lt;span class=&quot;c1&quot;&gt;# If this is set, 'root' will not be able to ssh in and they&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# will get a message to login instead as the above $user (ubuntu)&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;disable_root&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
 
   &lt;span class=&quot;c1&quot;&gt;# This will cause the set+update hostname module to not operate (if true)&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;preserve_hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;false&lt;/span&gt;
 
   &lt;span class=&quot;na&quot;&gt;rsyslog&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;remotes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
           &lt;span class=&quot;na&quot;&gt;log_serv&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;@synology.homeops.tech:514&quot;&lt;/span&gt;
 
   &lt;span class=&quot;c1&quot;&gt;# Downloads the golang package&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;jq&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;curl&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;git&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;qemu-guest-agent&lt;/span&gt;
   &lt;span class=&quot;c1&quot;&gt;# Add apt repositories&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;apt_sources&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;deb http://apt.puppetlabs.com buster puppet6&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;keyid&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;D6811ED3ADEEB8441AF5AA8F4528B6CD9E61EF26'&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;puppet6.list&lt;/span&gt;
 
   &lt;span class=&quot;c1&quot;&gt;# Run 'apt-get update' on first boot&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;apt_update&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
 
   &lt;span class=&quot;na&quot;&gt;puppet&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;package_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;puppet-agent'&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;conf_file&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/puppetlabs/puppet/puppet.conf'&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;csr_attributes_path&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/etc/puppetlabs/puppet/csr_attributes.yaml'&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;conf&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;agent&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;server&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;puppet.homeops.tech&quot;&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;certname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;%f&quot;&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;csr_attributes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;custom_attributes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;s&quot;&gt;1.2.840.113549.1.9.7&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;342thbjkt82094y0uthhor289jnqthpc2290&lt;/span&gt;
         &lt;span class=&quot;na&quot;&gt;extension_requests&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;na&quot;&gt;pp_preshared_key&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;342thbjkt82094y0uthhor289jnqthpc2290&lt;/span&gt;
 
   &lt;span class=&quot;na&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;UTC'&lt;/span&gt;
 
   &lt;span class=&quot;na&quot;&gt;manage_resolv_conf&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
 
   &lt;span class=&quot;na&quot;&gt;resolv_conf&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;nameservers&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.53.60'&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.53.70'&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;searchdomains&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;homeops.tech&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;domain&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;homeops.tech&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;
 
   &lt;span class=&quot;na&quot;&gt;datasource_list&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;ConfigDrive&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
   &lt;span class=&quot;na&quot;&gt;datasource&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;na&quot;&gt;ConfigDrive&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
       &lt;span class=&quot;na&quot;&gt;dsmode&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So as you can see , this cloud-init handles the the basics of creating a backup account, and then bootstraps puppet. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;csr_attributes&lt;/code&gt; can be use to then allow autosigning and classification of the node in puppet. I enable the ConfigDrive data source here as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxmox&lt;/code&gt; actually supports cloud-init out of the box. This allows an ISO image to contain extra node specific data such as the IP address of the node. I will be expierementing with using the SD card slot on my servers to bootstrap some of this local data from my servers in the future.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Again a little hand wavy here with the csr_attributes as they can’t be node specific. Thats v2 and can be fixed with cloud-drives and such.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Cloud-init Broker&lt;/h1&gt;

&lt;script src=&quot;https://gist.github.com/e6e8c674e192ca7fa6d2be7b69ef2998.js?file=install.erb&quot;&gt; &lt;/script&gt;

&lt;p&gt;You can check out the &lt;a href=&quot;https://gist.github.com/acidprime/e6e8c674e192ca7fa6d2be7b69ef2998&quot;&gt;gist&lt;/a&gt; for the configuration yaml for the broker. However lets take a look at what the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;install.erb&lt;/code&gt; script looks like. This script is essentially the payload for the cloud-init process. It will create a cloud-config and then run the final boot steps for cloud init. Assuming everything was successful it will phone home to razor and mark the node as installed. This by the way showcases one of the powers of razor,
which is to interpolate ruby templates on files by adding metadata and node data dyanmically.&lt;/p&gt;

&lt;h1&gt;Buster Task&lt;/h1&gt;

&lt;script src=&quot;https://gist.github.com/a24a415a21c0cdb83622b282827fb10e.js?file=preseed.erb&quot;&gt; &lt;/script&gt;

&lt;p&gt;In my example I am installing debian buster. At the time of this writing the razor server rather predictably only had a “task” for wheezy. Updating for buster was a minor  pain however it also works with the cloud-init broker to enable a new systemd item in liue of the rc.local file. You can find a full buster task in &lt;a href=&quot;https://gist.github.com/acidprime/a24a415a21c0cdb83622b282827fb10e&quot;&gt;this gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A few notes here on this preseed&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;% &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;node.facts[&lt;span class=&quot;s1&quot;&gt;'is_virtual'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true&lt;/span&gt; %&amp;gt;
d-i partman-auto/disk string /dev/sda
&amp;lt;% &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; %&amp;gt;
d-i partman-auto/disk string /dev/nvme0n1
&amp;lt;% end %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The virtual machines I use in proxmox are scsi emulated storage controllers. The Intel NUC on the other hand is an M.2 Nvme.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sh &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'set -- $(vgs --rows --noheadings | head -n 1); for vg in &quot;$@&quot;; do swapoff &quot;/dev/$vg/swap&quot;; vgremove -f &quot;$vg&quot;; done; set -- $(pvs --rows --noheadings | head -n 1); for pv in &quot;$@&quot;; do pvremove -f &quot;$pv&quot;; done'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This little script is used to remove the volume group as its name conflicts given I have static DHCP reservations. In other words the hostname is always the same in Netboot or Regular boot.&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/a24a415a21c0cdb83622b282827fb10e.js?file=razor_systemd.erb&quot;&gt; &lt;/script&gt;

&lt;p&gt;The new systemd item is simply a runner for the postinstall script that calls cloud-init&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Cloud-init seems well documented in some ways and not in others. My initial assumption was that I would not have to run these commands if I simply enabled the systemd items for cloud-init. However in testing that didn’t work and so the script is essentially running cloud-init.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The updated task and the custom broker above are essentially modified versions of the ones you find &lt;a href=&quot;https://github.com/acidprime/puppet-razor/tree/master/files&quot;&gt;here&lt;/a&gt;. I might add these to my fork in the future, but at the moment as they are site specific I add them to my profile modules’ files directory.&lt;/p&gt;
</description>
                <pubDate>Wed, 15 Jul 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/07/15/Razor-and-Cloud-Init/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/07/15/Razor-and-Cloud-Init/</guid>
                
                <category>puppet</category>
                
                <category>isc-dhcpd</category>
                
                <category>hiera</category>
                
                <category>how to</category>
                
                <category>razor</category>
                
                <category>terraform</category>
                
                
            </item>
        
            <item>
                <title>Managing DHCP with Puppet</title>
                <description>&lt;p&gt;In my previous post on managing &lt;a href=&quot;http://www.homeops.tech/2020/06/06/DNS-With-Puppet/&quot;&gt;DNS with Puppet&lt;/a&gt; I walked you through the code to configure an internal DNS domain with puppet. In this post I will cover setting up a DHCP server that supports IP reservations and has failover configured. I use this with two raspberry pis that also provide my DNS. While DHCP might often be ran off your router, in a home lab you might want to run DHCP in a separate VLAN for testing things out like PXE booting.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;puppet&lt;/td&gt;
            &lt;td&gt;6.21.0&lt;/td&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;dhcpd&lt;/td&gt;
            &lt;td&gt;isc-dhcpd-4.4.1&lt;/td&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
            &lt;td&gt;20.04&lt;/td&gt;
            &lt;td&gt;server&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;I run this all on a set of two raspberry pis’&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Puppetfile&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'dhcp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git@github.com:puppetlabs/puppetlabs-dhcp.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'b5925938188787faad99fdb52f294796e527a3d1'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'nodejs'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/voxpupuli/puppet-nodejs.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v8.1.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'staging'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/nanliu/puppet-staging.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:commit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'b466d93f8deb0ed4d9762a17c3c38f356aa833ee'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1&gt;Installing DHCPD&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'::dhcp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;nameservers&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'192.168.53.60'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'192.168.53.70'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ntpservers&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'time.homeops.tech'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;interfaces&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'eth0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;dnsdomain&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'homeops.tech'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;extra_config&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;EOS&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;space&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;APC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;APC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cookie&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;vendor-id&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vendor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;subclass&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;vendor-id&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;APC&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;vendor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;option&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;space&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;APC&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;APC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cookie&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1APC&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vendor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vendor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exists&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;option&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;iPXE&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bootstrap.ipxe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;filename&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;undionly.kpxe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$::ipaddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;EOS&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we are installing isc-dhcpd , which is the most common dhcp deamon on embedded systems. If your wireless gear is based on openwrt or if your networking gear is based on linux you might have this service already running. Given I have DNS running on my raspberry pis it only makes sense to add DHCP. This allows us in this example to configure DHCP options like PXE boot servers and the APC cookie configuration on my batter backups.&lt;/p&gt;

&lt;h1&gt;Setting up failover.&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;c&quot;&gt;# Hiera call is needed here as they are two different servers
&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'dhcp::failover'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;role&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dhcp::failover::role'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;peer_address&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dhcp::failover::peer_address'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I have two rasperry pis and unlike DNS that has its own client side failure abilities DHCP requires a server side configuration for failure protection. This allows me to reboot,reimage or reconfigure my running DHCP servers without bumping Netflix offline.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;in my experience DHCP failover works best with reservations. In the event of a failure the pool is cut in half , however those nodes with reservations will continue to receives their IPs. This keeps me honest in updating the yaml I use to manage this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This hiera lookup is essentially just a per node configuration. In the example hierarchy we setup in configuring DNS we added this line:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;nodes/%{::trusted.certname}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I have two DHCP servers &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hank.homeops.tech&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dean.homeops.tech&lt;/code&gt; So my yaml configuration is stored in my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; directory as follows&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;s&quot;&gt;nodes/&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;├── dean.wallcity.org.yaml&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;├── hank.wallcity.org.yaml&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;└── puppet.wallcity.org.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hank is the primary so that servers configuration is:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;dhcp::failover::role: 'primary'&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;dhcp::failover::peer_address: '192.168.53.70'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Dean is secondary/failover node and its configuration is:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;dhcp::failover::role: 'secondary'&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;dhcp::failover::peer_address: '192.168.53.60'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While there are many ways of making this information dynamic, you likely want to keep things simple given these servers are some of the first needed to get things rolling in your lab.&lt;/p&gt;

&lt;h2&gt;Configuring an IP Pool&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;dhcp::pool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'homeops.tech'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;network&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'192.168.53.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;mask&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'255.255.255.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;range&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'192.168.53.165 192.168.53.200'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;gateway&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'192.168.53.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we create a range of IPs form &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;165&lt;/code&gt; to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;200&lt;/code&gt;. The DHCP reservations should be outside this range.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Keep in mind this pool is cut in half during failover.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Load Static Reservations&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;nv&quot;&gt;$dhcp_hosts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dhcp_hosts'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;create_resources&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dhcp::host'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$dhcp_hosts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we load in the DHCP hosts from hiera. This allows us (like DNS) to manage this with YAML files. In my case I create a file named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dhcp.yaml&lt;/code&gt; in the hierarchy to contain these entries. This data can then be consumed by many other service , like icinga and razor-server.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: I need to upgrade this for completeness to the .each syntax in Puppet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Adding static entries is as simple as adding entries to the hash:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dhcp.yaml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;dhcp_hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;aurora&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mac&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;14:B3:2F:0B:F1:15'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.53.16'&lt;/span&gt; 
  &lt;span class=&quot;na&quot;&gt;echo_dot&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;mac&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;44:65:0D:49:F9:47'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ip&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.53.51'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;Monitoring with Monit&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/monit.png&quot; alt=&quot;Monit&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'monit'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;httpd&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;httpd_address&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$::ipaddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;httpd_password&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$uper$secret'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;monit::check&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'dhcpd'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'check process isc-dhcp-server with pidfile /run/dhcp-server/dhcpd.pid 
    start program = &quot;/etc/init.d/isc-dhcp-server start&quot;
    stop  program = &quot;/etc/init.d/isc-dhcp-server stop&quot;
    if failed host 127.0.0.1 port 67 type udp then alert
  '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Because of the criticality of this service I want to make sure it is always running, as we saw with DNS we can add monit. We can run this on the local box as well to have status page for the services.&lt;/p&gt;

&lt;h1&gt;Installing Glass (DHCP Web interface)&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'::nodejs'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;manage_package_repo&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;nodejs_dev_package_ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;npm_package_ensure&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'forever'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'npm'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;vcsrepo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/glass-isc-dhcp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;provider&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/Akkadius/glass-isc-dhcp.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;revision&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'10102a670909f30f7a471837826cf863b18ba0b0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kp&quot;&gt;notify&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'install'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'install'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;s1&quot;&gt;'chmod u+x ./bin/ -R &amp;amp;&amp;amp; chmod u+x *.sh &amp;amp;&amp;amp; mkdir -p logs &amp;amp;&amp;amp; npm install'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;cwd&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/glass-isc-dhcp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;refreshonly&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;cron&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'glass_startup'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'cd /opt/glass-isc-dhcp &amp;amp;&amp;amp; /usr/local/bin/forever --minUptime 10000 --spinSleepTime 10000 -a -o ./logs/glass-process.log -e ./logs/glass-error.log ./bin/www'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;special&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'reboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;target&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'root'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;user&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'root'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kp&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'forever'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In configuring the raspberry pis you might miss having the standard web interface that comes with most home routers version of DHCP. This can be helpful for finding MAC addresses on opaque machines, like smart speakers. I Have been using the Glass DHCP web interface for a while now and while not every feature is useful,given I’m managing the configuration with puppet, I find the overview page useful for viewing the lease files. There is no official installer for this tool but a little puppet code goes along way here.&lt;/p&gt;

&lt;h1&gt;Optional: Enable PXE &amp;amp; TFTP Services&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'tftp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/var/lib/tftpboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;owner&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'tftp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;group&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;s1&quot;&gt;'tftp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;mode&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'0755'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'tftp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;directory&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/var/lib/tftpboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;address&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$::ipaddress&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;options&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'--verbose --permissive --secure --timeout 120'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;inetd&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# The iPXE kernel will fetch a bootstrap.ipxe file, that then aims a chain
&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# loader at the Razor server to determine how to proceed.  For instance, new
&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# machines are simply told to load a microkernel.
&lt;/span&gt;  &lt;span class=&quot;c&quot;&gt;# The bootstrap is static, but Razor likes to be the one to craft it.
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;staging::file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bootstrap.ipxe'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;target&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/var/lib/tftpboot/bootstrap.ipxe'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;http://razor.homeops.tech:8150/api/microkernel/bootstrap?nic_max=1&amp;amp;http_port=8150&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;curl_option&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'--insecure'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;kp&quot;&gt;require&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/var/lib/tftpboot'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;tftp::file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bootstrap.ipxe'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;mode&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;s1&quot;&gt;'0755'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/var/lib/tftpboot/bootstrap.ipxe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# undionly.kpxe
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;wget::fetch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'http://boot.ipxe.org/undionly.kpxe'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;destination&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/var/lib/tftpboot/undionly.kpxe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;-&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;tftp::file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'undionly.kpxe'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;mode&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;s1&quot;&gt;'0755'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/var/lib/tftpboot/undionly.kpxe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While this not strictly needed in every environment, I find the inclusion of TFT and PXE to be generally connected to my DHCP ecosystem.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
      &lt;span class=&quot;k&quot;&gt;if &lt;/span&gt;exists user-class and option user-class &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;iPXE&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          filename &lt;span class=&quot;s2&quot;&gt;&quot;bootstrap.ipxe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
          filename &lt;span class=&quot;s2&quot;&gt;&quot;undionly.kpxe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
      next-server &lt;span class=&quot;nv&quot;&gt;$:&lt;/span&gt;:ipaddress&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we saw earlier we setup the DHCP options to point to the needed files to PXE boot a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;razor-server&lt;/code&gt; implementation.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note that you need to comment out this section unless you have setup razor-server. Watch here for a future razor article&lt;/p&gt;
&lt;/blockquote&gt;
</description>
                <pubDate>Wed, 15 Jul 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/07/15/DHCP-With-Puppet/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/07/15/DHCP-With-Puppet/</guid>
                
                <category>puppet</category>
                
                <category>isc-dhcpd</category>
                
                <category>hiera</category>
                
                <category>iot</category>
                
                <category>how to</category>
                
                <category>ha</category>
                
                <category>raspberry pi</category>
                
                <category>monit</category>
                
                <category>systemd</category>
                
                
            </item>
        
            <item>
                <title>Managing DNS with Puppet</title>
                <description>&lt;p&gt;One of the more important things in configuration management is DNS. In home labs we often don’t have DNS out of box. Some folks do use &lt;a href=&quot;https://www.raspberrypi.org/blog/pi-hole-raspberry-pi/&quot;&gt;pi-holes&lt;/a&gt; but often don’t configure custom domains.
I often use static reservations for all my IOT devices. This means all devices on my network can use DNS names to configure and talk to each other with those respective static’ish IPs. In this post I will show you how I use Puppet to setup an internal DNS domain.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;puppet&lt;/td&gt;
            &lt;td&gt;6.21.0&lt;/td&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;bind&lt;/td&gt;
            &lt;td&gt;9.16.1-Ubuntu&lt;/td&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;ubuntu&lt;/td&gt;
            &lt;td&gt;20.04&lt;/td&gt;
            &lt;td&gt;server&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;blockquote&gt;
  &lt;p&gt;I run this all on a set of two raspberry pis’&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Puppetfile&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'dns'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git://github.com/amateo/puppet-dns.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:commit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'15805a8a6577bea6b3dfab1d8951369c925b5e6a'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'monit'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/acidprime/puppet-monit.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:commit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'f94712677271ccab0fc990478e31a7f37cb9791d'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'collectd'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git@github.com:pdxcat/puppet-module-collectd.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v12.2.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'hiera'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/hunner/puppet-hiera.git'&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v2.1.1'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'resolv_conf'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git@github.com:saz/puppet-resolv_conf.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:tag&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v3.0.5'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'systemd'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/camptocamp/puppet-systemd.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'2.12.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'timezone'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/kogitoapp/puppet-timezone.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v2.1.1'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Using a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;monit&lt;/code&gt; fork here as the original author doesn’t update OS version quickly enough for me.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;Configuring NTP&lt;/h1&gt;

&lt;p&gt;Given modern requirements like DNSSec , time sync is an about necessity for dns servers.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'systemd'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;manage_timesyncd&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;ntp_server&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'0.pool.ntp.org'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.pool.ntp.org'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;fallback_ntp_server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'2.pool.ntp.org'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'4.pool.ntp.org'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'timezone'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;timezone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'UTC'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'ntp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;servers&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pool&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ntp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'1.pool.ntp.org'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;autoupdate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'ntpdate'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While this goes most of the way, there is a chicken before the egg scenerio here, that ntp requires DNS. I work around that on boot with the systemd implementation. See below.&lt;/p&gt;

&lt;h1&gt;Installing Bind&lt;/h1&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
  &lt;span class=&quot;nv&quot;&gt;$dns_domain&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'homeops.tech'&lt;/span&gt;


  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dns::server'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;enable_default_zones&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;dns::server::options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/etc/bind/named.conf.options'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;check_names_master&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'fail'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;check_names_slave&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'warn'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;dnssec_enable&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;forwarders&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'205.171.3.65'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'205.171.2.65'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;statistic_channel_ip&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'127.0.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;statistic_channel_port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8053&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The code above is an example of configuring bind9 without the default zones.
I’m setting this server up with forwarders as I find that media streaming and such seems to work best with the content distro networks when I use my ISP’s DNS.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’m making an anecdotal assumption here as its hard to verify this behavior but seems like the most likely conclusion&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Adding DNS Zones&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;dns::zone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dns_domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;soa&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$::fqdn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;soa_email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;root.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;${::fqdn}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;nameservers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$::hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Reverse Zone
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;dns::zone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'53.168.192.IN-ADDR.ARPA'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;soa&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$::fqdn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;soa_email&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;root.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;${::fqdn}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;nameservers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$::hostname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;c&quot;&gt;# Apex record e.g. homeops.tech vs www.homeops.tech
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;dns::record&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;apex_alias&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;${dns_domain}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;zone&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dns_domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;host&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'@'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;record&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'A'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;data&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'192.168.53.222'&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we create a new DNS zone , and set the nameservers to the hostname of the machine.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;192.168.22.222 is the address of a blob server that runs the rendered for my website before I push it to the web&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Configuring records&lt;/h2&gt;

&lt;p&gt;Now that we have out DNS zones configured we can add record. While you could do this in code, I find the amount of DNS records over time mean something like yaml is better. Further it also means you can load this data set into other tools e.g. add automatic testing with icinga. Stay tuned for a future article on icingaweb2.&lt;/p&gt;

&lt;p&gt;First lets setup Hiera. Hiera is a data ingestion engine builtin to puppet. If you just setup your Puppet Server using my &lt;a href=&quot;http://www.homeops.tech/2020/02/01/Provision-Puppetserver-with-Packer/&quot;&gt;previous article&lt;/a&gt; then you need to manage hiera’s configuration.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'::hiera'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;backends&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'yaml'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;datadir&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/etc/puppetlabs/code/environments/%{environment}/data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;hierarchy&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'nodes/%{::trusted.certname}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'environments/%{environment}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'dhcp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'dns'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'common'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Bootstrapping puppet can have some chicken before the egg scenarios.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is an example configuration you can apply to your Puppet Master to configure hiera with support for a file called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dns.yaml&lt;/code&gt; in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;data&lt;/code&gt; directory of your &lt;a href=&quot;https://puppet.com/docs/pe/2019.8/control_repo.html&quot;&gt;control repo&lt;/a&gt;.
The most important idea here is that hiera is using yaml files that are dynamically name e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%{::trusted.certname}&lt;/code&gt; or statically named e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dns&lt;/code&gt;. For our purposes we will mostly be using static entries for our DNS records.&lt;/p&gt;

&lt;p&gt;Lets add code to pull DNS records in from hiera:&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;c&quot;&gt;# Resource Defaults
&lt;/span&gt;  &lt;span class=&quot;nc&quot;&gt;Dns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;zone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dns_domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ptr&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nc&quot;&gt;Dns&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Record&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Cname&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;zone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dns_domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'a_records'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dns::record::a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;{value['data']}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nf&quot;&gt;hiera&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'cname_records'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;dns::record::cname&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;{value['data']}&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This code snippet will iterate over the keys in hiera. You can create more then A and CNAME but for my purposes, these and the automatically created PTR records normally are enough.
Lets look at what our dns.yaml file looks like in this configuration:&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dns.yaml&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# DNS Records&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;cname_records&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;grafana&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;proxmox.homeops.tech'&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;www&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;proxmox.homeops.tech'&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;a_records&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;proxmox&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.53.38'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;linux'&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;alexa&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;192.168.53.206'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;iot'&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The nice thing about this configuration is that to add DNS records you now simply edit the yaml.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can safely ignore the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tag&lt;/code&gt; key here, it will be used in future articles to classify these entries for monitoring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Installing useful tools&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dnstop'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;Monitoring &amp;amp; Reporting&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;monit::check&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bind9'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'check process named with pidfile /var/run/named/named.pid 
    start program = &quot;/etc/init.d/named start&quot;
    stop  program = &quot;/etc/init.d/named stop&quot;
    if failed host 127.0.0.1 port 53 type tcp protocol dns then restart
    if failed host 127.0.0.1 port 53 type udp protocol dns then restart
  '&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While systemd is all the rage, I like pants and suspenders when it comes to critical services.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'collectd::plugin::bind'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;url&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'http://localhost:8053/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can also load the metrics into collect/graphite/graphana. This is configured above in the options:&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;statistic_channel_ip&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'127.0.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;statistic_channel_port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;8053&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can checkout my article on setting up &lt;a href=&quot;http://www.homeops.tech/2020/05/20/Graphite-And-Grafana-With-Puppet/&quot;&gt;Graphite/Grafana/Collectd here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Split DNS on VPN&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;dns::acl&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'trusted'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;data&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'192.168.53.221/32'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'192.168.54.0/24'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use zerotier for my “vpn” in addition to swan. I need to allow these clients to access the DNS server. in this configuration I setup the hiera range of my subnet (vpn) and the .54 address space I use with zerotier.&lt;/p&gt;

&lt;h2&gt;Configure resolv.conf&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'resolv_conf'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;nameservers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'127.0.0.1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'192.168.53.60'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'192.168.53.70'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;domainname&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$dns_domain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once we have tested the DNS server we can set it to perform resolutions with itself.&lt;/p&gt;

&lt;h2&gt;Systemd Hacks&lt;/h2&gt;

&lt;p&gt;Given i normally use raspberry pi’s I can’t rely on timesync working out of the box. I work around that by waiting until after boot (and the network is online) to sync with an IP address of a known NTP server.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'ntpdate'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
   &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

 &lt;span class=&quot;c&quot;&gt;# Setup the users custom shell as pass through to docker
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/bin/atboot.sh&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;owner&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;mode&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'0755'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;   &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SHELL&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;L&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;#!/bin/bash -x
&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ntpdate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;u&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;209.114&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;111.1&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bind9&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;restart&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;dig&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;google&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;com&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;127.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0.1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;SHELL&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 

  &lt;span class=&quot;nv&quot;&gt;$_timer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;EOT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Unit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;Description&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Run&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;DNS&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;checks&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;startup&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;Wants&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;online&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;After&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;online&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;OnBootSec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;OnUnitActiveSec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; 
  &lt;span class=&quot;nc&quot;&gt;Unit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;timesync&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;service&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;EOT&lt;/span&gt;
  
  &lt;span class=&quot;nv&quot;&gt;$_service&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;EOT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;oneshot&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;ExecStartPre&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'until ping -c 1 209.114.111.1 ; do sleep 1; done;'&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;ExecStart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;usr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atboot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;TimeoutSec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;StandardOutput&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;journal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;StandardError&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;journal&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;console&lt;/span&gt;
  &lt;span class=&quot;nc&quot;&gt;EOT&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;systemd::timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'atboot.timer'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;timer_content&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_timer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;service_unit&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'timesync.service'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;service_content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$_service&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;active&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;enable&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This should run and make sure during a reboot or outage that your server syncs time even when DNS is broken&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;● timesync.service
     Loaded: loaded (/etc/systemd/system/timesync.service; static; vendor preset: enabled)
     Active: inactive (dead) since Tue 2021-02-16 12:27:00 PST; 31s ago
TriggeredBy: ● atboot.timer
    Process: 248739 ExecStartPre=/bin/sh -c until ping -c 1 209.114.111.1 ; do sleep 1; done; (code=exited, status=0/SUCCESS)
    Process: 248742 ExecStart=/usr/local/bin/atboot.sh (code=exited, status=0/SUCCESS)
   Main PID: 248742 (code=exited, status=0/SUCCESS)

Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: ;; QUESTION SECTION:
Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: ;google.com.                        IN        A
Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: ;; ANSWER SECTION:
Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: google.com.                89        IN        A        172.217.3.206
Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: ;; Query time: 19 msec
Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: ;; SERVER: 127.0.0.1#53(127.0.0.1)
Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: ;; WHEN: Tue Feb 16 12:27:00 PST 2021
Feb 16 12:27:00 dns1.homeops.tech atboot.sh[248941]: ;; MSG SIZE  rcvd: 83
Feb 16 12:27:00 dns1.homeops.tech systemd[1]: timesync.service: Succeeded.
Feb 16 12:27:00 dns1.homeops.tech systemd[1]: Finished timesync.service.

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see similar output to this, if your systemd item fails you can monitor its failures to determine if DNS is down due to timesync issues.&lt;/p&gt;
</description>
                <pubDate>Sat, 06 Jun 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/06/06/DNS-With-Puppet/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/06/06/DNS-With-Puppet/</guid>
                
                <category>puppet</category>
                
                <category>bind</category>
                
                <category>dns</category>
                
                <category>hiera</category>
                
                <category>iot</category>
                
                <category>how to</category>
                
                <category>ha</category>
                
                <category>raspberry pi</category>
                
                <category>monit</category>
                
                <category>systemd</category>
                
                
            </item>
        
            <item>
                <title>Graphite, Grafana and Collectd</title>
                <description>&lt;p&gt;I recently moved my existing esxi hypervisors to &lt;a href=&quot;https://www.proxmox.com/en/&quot;&gt;ProxMox&lt;/a&gt; to have more control then the esxi shell allowed. This allows me to run puppet natively on the hyper visor host. As part of this upgrade I installed an old SSD and ram into my 2011 Mac Mini. While doing so I broke the small traces that attach the cooling fan. After some research I found many people have done the same and just leave it fanless. This presented me with a great opportunity to graph the
the various temp sensors as I tried different cooling methods.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;puppet&lt;/td&gt;
            &lt;td&gt;6.21.0&lt;/td&gt;
            &lt;td&gt;Debian&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Debian&lt;/td&gt;
            &lt;td&gt;10.7&lt;/td&gt;
            &lt;td&gt;buster&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Puppetfile&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'graphite'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git@github.com:echocat/puppet-graphite.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v8.0.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'grafana'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git@github.com:echocat/puppet-grafana.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v1.2.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'elasticsearch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/elasticsearch/puppet-elasticsearch.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'7.0.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'elastic_stack'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/elastic/puppet-elastic-stack.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'7.0.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'apache'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://github.com/puppetlabs/puppetlabs-apache'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1.5.0'&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;mod&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'collectd'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git@github.com:pdxcat/puppet-module-collectd.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;:ref&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'v12.2.0'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;New to puppet? Checkout my how to on installing a &lt;a href=&quot;http://www.homeops.tech/2020/02/01/Provision-Puppetserver-with-Packer/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puppetserver&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We can install the packages needed for graphite to configure and store data.&lt;/p&gt;

&lt;h2&gt;Installing Graphite&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'graphite-carbon'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'graphite'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;gr_apache_24&lt;/span&gt;               &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;gr_web_cors_allow_from_all&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;secret_key&lt;/span&gt;                 &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$uper$ecret?'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;gr_web_server&lt;/span&gt;           &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'none'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;gr_web_user&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'www-data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;gr_web_group&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'www-data'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;gr_disable_webapp_cache&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;gr_storage_schemas&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'carbon'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;pattern&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'^carbon\.'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;retentions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1m:90d'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'default'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;pattern&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'.*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;retentions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1m:30m,1m:1d,5m:2y'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'collectd'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;pattern&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'^collectd.*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;retentions&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1m:30m,1m:1d,5m:2y'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here we can install Graphite and configure it with a storage scheme for collectd. The important bits here are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gr_web_server =&amp;gt; 'none',&lt;/code&gt; which allows us to configure graphite to be hosted with apache.&lt;/p&gt;

&lt;h1&gt;Setting up a Webserver&lt;/h1&gt;

&lt;p&gt;As both Graphite and Grafana can use apache lets start with a default installation.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'::apache'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;n&quot;&gt;package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'libffi-dev'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2&gt;Setting up Graphite Vhost&lt;/h2&gt;

&lt;p&gt;Once apache is running we can setup a vhost for Graphite as follows&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;apache::vhost&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;graphite.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;${::domain}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;port&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'80'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;docroot&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/graphite/webapp'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;wsgi_application_group&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%{GLOBAL}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;wsgi_daemon_process&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'graphite'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;wsgi_daemon_process_options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;processes&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'5'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;py&quot;&gt;threads&lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'5'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;name&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%{GROUP}'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;inactivity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;timeout&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'120'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;wsgi_import_script&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/graphite/conf/graphite.wsgi'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;wsgi_import_script_options&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;group&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'graphite'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;py&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'%{GLOBAL}'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;aliases&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
           &lt;span class=&quot;py&quot;&gt;alias&lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/content/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/graphite/webapp/content/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
           &lt;span class=&quot;py&quot;&gt;alias&lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/static/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
           &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt;             &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/graphite/static/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
   &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;wsgi_process_group&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'graphite'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;wsgi_script_aliases&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'/'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/graphite/conf/graphite.wsgi'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;headers&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'set Access-Control-Allow-Origin &quot;*&quot;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'set Access-Control-Allow-Methods &quot;GET, OPTIONS, POST&quot;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'set Access-Control-Allow-Headers &quot;origin, authorization, accept&quot;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;directories&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/media/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'deny,allow'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;allow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'from all'&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/graphite/static/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'deny,allow'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;allow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'from all'&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;path&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/opt/graphite/webapp/content/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;order&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'deny,allow'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;py&quot;&gt;allow&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'from all'&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is more or less the example in the modules README with a small tweak:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;...
{ 
  alias            =&amp;gt; '/static/',
  path             =&amp;gt; '/opt/graphite/static/',
},
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This undocumented line is the most important as otherwise you are greeted with a blank site with only headers.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/opt/graphite/conf/graphite.wsgi&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'present'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/opt/graphite/conf/graphite.wsgi.example&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We now can copy the example .wsgi file&lt;/p&gt;

&lt;h2&gt;Setup&lt;/h2&gt;

&lt;p&gt;We now need to init the graphite django configuration. I should show you how to do this with an exec here, but honestly I often do this manually on first build with the following commands&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PYTHONPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/graphite/webapp django-admin.py migrate &lt;span class=&quot;nt&quot;&gt;--settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;graphite.settings &lt;span class=&quot;nt&quot;&gt;--run-syncdb&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PYTHONPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/graphite/webapp django-admin.py createsuperuser &lt;span class=&quot;nt&quot;&gt;--settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;graphite.settings
&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-H&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;PYTHONPATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/graphite/webapp django-admin.py collectstatic &lt;span class=&quot;nt&quot;&gt;--noinput&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;graphite.settings
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should be able to verify the installation by sending some example metrics too it:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2003
&lt;span class=&quot;nv&quot;&gt;SERVER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;graphite.homeops.tech
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;local.random.diceroll 4 &lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; +%s&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | nc &lt;span class=&quot;nt&quot;&gt;-q0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SERVER&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3&gt;Installing ElasticSearch&lt;/h3&gt;

&lt;p&gt;To store the graphs in grafana we need an elasticsearch deployment. I actually don’t use this as I normally export the json and have puppet manage it so it can be redeployed at will. The following however is an example of getting elasticsearch up and running.&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'elasticsearch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;config&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'cluster.name'&lt;/span&gt;           &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'elk'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'node.name'&lt;/span&gt;              &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$::fqdn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'network.host'&lt;/span&gt;           &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'0.0.0.0'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'discovery.type'&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'single-node'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'http.cors.allow-origin'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'http.cors.enabled'&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'true'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'xpack.security.enabled'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'false'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'xpack.ml.enabled'&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'false'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'node.master'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'true'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'node.data'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'node.ingest'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'action.auto_create_index'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;restart_on_change&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;manage_repo&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;init_defaults&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'ES_USER'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'elasticsearch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'ES_GROUP'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'elasticsearch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'MAX_OPEN_FILES'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'65535'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'MAX_LOCKED_MEMORY'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'unlimited'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'JAVA_HOME'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/usr'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;es_instance_conn_validator&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'elk'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'localhost'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;port&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'9200'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I use this elasticsearch for an ELK stack (look forward a future article!) so thats why I call it elk here.&lt;/p&gt;

&lt;p&gt;You should be able to verify the installation with the following:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl &lt;span class=&quot;nt&quot;&gt;-X&lt;/span&gt; GET &lt;span class=&quot;s2&quot;&gt;&quot;localhost:9200/_cluster/health?wait_for_status=yellow&amp;amp;timeout=50s&amp;amp;pretty&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cluster_name&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;elk&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;yellow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;timed_out&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number_of_nodes&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number_of_data_nodes&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;active_primary_shards&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;active_shards&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;relocating_shards&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;initializing_shards&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;unassigned_shards&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;delayed_unassigned_shards&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number_of_pending_tasks&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;number_of_in_flight_fetch&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;task_max_waiting_in_queue_millis&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;active_shards_percent_as_number&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;87.5&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;Single shard deployments will show yellow not green/&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Installing Grafana&lt;/h2&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'grafana'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;graphite_host&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;graphite.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;${::domain}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;elasticsearch_host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;localhost&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;elasticsearch_port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;9200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’m using an older version of grafana as I have some older dashboards I don’t want to update.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;Dashboards&lt;/h3&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Collectd Dashboard
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/opt/grafana/app/dashboards/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;ensure&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;source&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'puppet:///modules/profile/grafana/'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;recurse&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As mentioned, while its neat that grafana can store its data in ElasticSearch. I don’t actually use that. When I build a dashboard I export it and save it in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;profile/files/grafana&lt;/code&gt; directory of my module. This the is recusively copied into grafana’s web directory. This means when I build or rebuild my grafana deployments I don’t have to import elasticsearch data. It also means I can use templates to build dynamic dashboards that are copied in to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/opt/grafana/app/dashboards/&lt;/code&gt;. These are then available using the following URL e.g. for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;collectd.json&lt;/code&gt; : &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://grafana.homeops.tech/#/dashboard/file/collectd.json&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;Setting up collectd&lt;/h2&gt;

&lt;p&gt;As I mentioned I wanted to monitor the temperature of the 2011 mac mini server I use as the Proxmox virtualisation box. Its my backup box and so I wanted to see if any of the USB fans I had laying around the house would actually work to cool it. To start graphing the temperature I needed to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sensors&lt;/code&gt; package on debian/proxmox.&lt;/p&gt;

&lt;p&gt;This is as simple as appling this configuration to that node:&lt;/p&gt;

&lt;div class=&quot;language-puppet highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'collectd::plugin::sensors'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;manage_package&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This installs the sensors package. I also for good measure (and maybe required) ran the following to detect all sensors on the system.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sensors-detect
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;sensors
coretemp-isa-0000
Adapter: ISA adapter
Package &lt;span class=&quot;nb&quot;&gt;id &lt;/span&gt;0:  +53.0°C  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;high &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +86.0°C, crit &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +100.0°C&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Core 0:        +51.0°C  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;high &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +86.0°C, crit &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +100.0°C&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Core 1:        +53.0°C  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;high &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +86.0°C, crit &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +100.0°C&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Core 2:        +46.0°C  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;high &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +86.0°C, crit &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +100.0°C&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Core 3:        +49.0°C  &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;high &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +86.0°C, crit &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; +100.0°C&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/sensors.png&quot; alt=&quot;Sensors&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I was pleasantly surprised to find most supported by the package.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;While collectd doesn’t resolve them , a long term plan is to rewrite the json using &lt;a href=&quot;https://logi.wiki/index.php/SMC_Sensor_Codes&quot;&gt;this table&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/graphite-config.png&quot; alt=&quot;Graphite Config&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Create the dashboard is simple as creating a dynamic entry for the node as show above.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/sad-mini.jpg&quot; alt=&quot;SadMini&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As luck would have it the only USB fans I had was a gift that someone gave me years ago. It was a LED fan that I had since lost the windows-only install CD for. &lt;em&gt;Given the state of the mini it seemed appropriate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/usb_fan.png&quot; alt=&quot;USBFan&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Interestingly enough even at high load the fan managed to cool the SMC temp sensors ( and the CPU sensors) below the high/crit values.&lt;/p&gt;

&lt;p&gt;Suffice to say I have replacement server (intel NUC) on order , however I may keep this mini around given its working. Proxmox supports a cluster with my APC PDU where it would only power on in the event of failure.&lt;/p&gt;

&lt;p&gt;I’ll write that up if I get it working.&lt;/p&gt;
</description>
                <pubDate>Wed, 20 May 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/05/20/Graphite-And-Grafana-With-Puppet/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/05/20/Graphite-And-Grafana-With-Puppet/</guid>
                
                <category>graphite</category>
                
                <category>grafana</category>
                
                <category>puppet</category>
                
                <category>collectd</category>
                
                <category>how to</category>
                
                
            </item>
        
            <item>
                <title>Run Terraform In Docker</title>
                <description>&lt;p&gt;In my previous post on &lt;a href=&quot;http://www.homeops.tech/2020/03/15/Compile-Go-In-Docker/&quot;&gt;compiling go in docker&lt;/a&gt; I noted that it had many advantages. This is also true for tools like terraform. One of the major advantages of say &lt;a href=&quot;https://www.terraform.io/docs/cloud/index.html&quot;&gt;Terraform Cloud&lt;/a&gt; is the fact that you can pin or change your terraform version. Terraform like many configuration languages is not backwards compatible. Upgrading code , while easier then say puppet , can be complex
when you have multiple state files. Being able to selectively upgrade one terraform configuration while leaving the others pinned allows for more flexibility. Using docker means you don’t have to rely on your local machines copy or version compatibility across your team.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;docker&lt;/td&gt;
            &lt;td&gt;18.0.9&lt;/td&gt;
            &lt;td&gt;Ubuntu&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;terraform&lt;/td&gt;
            &lt;td&gt;12,13,14&lt;/td&gt;
            &lt;td&gt;Ubuntu&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/679c5fd0c32ac40c680d09d5b1aa5b63.js?file=Dockerfile&quot;&gt; &lt;/script&gt;

&lt;p&gt;The main thing to notice here is the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ARG version&lt;/code&gt; which allows you to pin your docker version. We do a multi-stage build here to copy terraform out of the upstream container.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This dockerfile runs terraform after init. It can take any argument you pass to the regular cli. I have a couple other additions which allow terraform to itself use docker but thats left to the reader (or another future article!).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;backend.tvars&lt;/code&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/679c5fd0c32ac40c680d09d5b1aa5b63.js?file=backend.tvars&quot;&gt; &lt;/script&gt;

&lt;p&gt;In this example I’m using s3 storage for state.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;variables.sh&lt;/code&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/679c5fd0c32ac40c680d09d5b1aa5b63.js?file=variables.sh&quot;&gt; &lt;/script&gt;

&lt;p&gt;You can send vars in anyway you would like, however in my case I might need some “active” vars like the current commit. This variables file works as a config file for the terraform stack. It is actually the only file you would need to update across multiple repos as well.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;functions.sh&lt;/code&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/679c5fd0c32ac40c680d09d5b1aa5b63.js?file=functions.sh&quot;&gt; &lt;/script&gt;

&lt;p&gt;This script uses functions to override the local invocations of the terraform command.&lt;/p&gt;

&lt;p&gt;Lets break this down…&lt;/p&gt;

&lt;h2&gt;AWS Credentials&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;     &lt;span class=&quot;nt&quot;&gt;--network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;credentials_network&quot;&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     ...
     &lt;span class=&quot;nt&quot;&gt;--build-arg&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;aws_container_credentials_relative_uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;AWS_CONTAINER_CREDENTIALS_RELATIVE_URI&lt;/span&gt;:?&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
     ...
     &lt;span class=&quot;nt&quot;&gt;--env&lt;/span&gt; AWS_CONTAINER_CREDENTIALS_RELATIVE_URI &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When you first configure terraform you use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform init&lt;/code&gt;. This downloads the plugins and potentially creates s3 objects. In the case you store your state remotely is say s3, you also need access to AWS credentials to access that s3 bucket. Because docker only has access to what you say you need to pass in any credentials. You could at this point simply pass the AWS credentials in as build args, however that’s decently insecure if your not using short lived credentials.&lt;/p&gt;

&lt;p&gt;Our solution is to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AWS_CONTAINER_CREDENTIALS_RELATIVE_URI&lt;/code&gt; var. This is a standard variable that is used by most of the AWS SDKs. As terraform is simply a wrapper around the golang aws sdk it also supports this. This URL is used to query the link local address &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;169.254.170.2&lt;/code&gt; for credentials. This way the creds are handed directly to the sdk and not saved in the container. The requirements for getting this up and running are to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;amazon-ecs-local-container-endpoints&lt;/code&gt;
container. There are multiple articles that cover this far better then I would. You can find the two most relevent &lt;a href=&quot;https://github.com/awslabs/amazon-ecs-local-container-endpoints/blob/mainline/docs/features.md#vend-credentials-to-containers&quot;&gt;here&lt;/a&gt; and &lt;a href=&quot;https://aws.amazon.com/blogs/compute/a-guide-to-locally-testing-containers-with-amazon-ecs-local-endpoints-and-docker-compose/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This variable is passed either through a build-arg directly but ends up simply being an environmental variable thats present at both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform init&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;terraform apply&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You may note that I’m not using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DOCKER_BUILDKIT&lt;/code&gt; in the build step of this container. Unfortunately at the time of this writing docker buildkit does not support attaching a network like the current implementation does. This is I believe scoped but not currently working.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Terraform variables&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TF_VAR_git_commit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;git rev-parse &lt;span class=&quot;nt&quot;&gt;--short&lt;/span&gt; HEAD&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
...
&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;var &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!TF_VAR*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do
  &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!var&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;.env
&lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
...
&lt;span class=&quot;nt&quot;&gt;--env-file&lt;/span&gt; .env &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
...
&lt;span class=&quot;nb&quot;&gt;unset&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;!TF_VAR*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These snippets allow you to declare any variable with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TF_VAR&lt;/code&gt; and have it passed to the container.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This file should be in your .gitignore if it contains sensitive values, consider instead using the secure AWS credentials to bootstrap access to secrets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apply.sh&lt;/code&gt;&lt;/p&gt;

&lt;script src=&quot;https://gist.github.com/679c5fd0c32ac40c680d09d5b1aa5b63.js?file=apply.sh&quot;&gt; &lt;/script&gt;

&lt;p&gt;Due the function being named terraform you, can simply remove the source line for the functions and this is essentially just a generic wrapper around the terraform commands. While &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init&lt;/code&gt; is handled differently e.g. its a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;build&lt;/code&gt; vs a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run&lt;/code&gt; all other terraform commands act identically to the command line. If a team member installed the latest version of terraform, they will not “accidentally” upgrade your state by doing an apply. The terraform version is pinned to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TERRAFORM_VERSION&lt;/code&gt; var we declared. This means this is likely a drop in replacement for any existing script you might have.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Given the caching aspects of docker this can also make things slightly more consistent for plugins. However until build kit supports docker networks, we won’t be able to use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--mount&lt;/code&gt; flag to prevent plugins from being downloaded on multiple containers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Terraform cloud&lt;/h2&gt;

&lt;p&gt;If you find this configuration useful then you likely will enjoy migrating to &lt;a href=&quot;https://app.terraform.io/&quot;&gt;Terraform Cloud&lt;/a&gt; as it supports pinned versions of terraform and shared states right out of the box. I normally try run most things in TFC when possible , however some builds need to run locally. E.g. Docker in Docker style builds.&lt;/p&gt;
</description>
                <pubDate>Tue, 21 Apr 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/04/21/Run-Terraform-In-Docker/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/04/21/Run-Terraform-In-Docker/</guid>
                
                <category>terraform</category>
                
                <category>hashicorp</category>
                
                <category>devops</category>
                
                <category>docker</category>
                
                <category>aws</category>
                
                <category>ecs</category>
                
                
            </item>
        
            <item>
                <title>Compile Go In Docker</title>
                <description>&lt;p&gt;I have recently been moving almost all of my workflows to docker. This makes allot of sense over time as things like your development environment can change from laptop to laptop or os to os. While I think something like &lt;a href=&quot;https://nixos.org/&quot;&gt;NixOs&lt;/a&gt; is a great step forward in the direction of a common development and delivery platform. I still tend to fallback to docker when building simple shell scripts that I need to share with members of my team. Running things in docker can mean that you can also
pin the version of the  given software or libraries which has some huge stability and repeatability implications over time. Something many people miss when sharing assets among each other.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;docker&lt;/td&gt;
            &lt;td&gt;20.10.2&lt;/td&gt;
            &lt;td&gt;Ubuntu&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;In an upcoming article I will cover how I use this same trick to selectively upgrade terraform code across a suite of lambdas. In the case of Golang, using docker has the major benefits e.g. its likely a container is my final output as well as my compile time environment. Most of the code I write ends up in one way or another on a serverless platform like AWS Lambda. Lambdas recently started support docker containers in liue of the standard zip file we had all grown accustom to. This means I can use the
environment to compile my code and then the resultant container to deploy it.&lt;/p&gt;

&lt;h1&gt;Dockerfile&lt;/h1&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; FROM golang:latest
 
 ARG target
 
 &lt;span class=&quot;c&quot;&gt;# Go build configuration&lt;/span&gt;
 ENV GO111MODULE=&quot;on&quot;
 ENV GOPRIVATE=&quot;github.com/homeops-tech/slackbot&quot;
 ENV GOOS=&quot;linux&quot;
 ENV CGO_ENABLED=&quot;0&quot;
 # Setup our container
 RUN mkdir /src
 COPY . /src/
 WORKDIR /src
 
 &lt;span class=&quot;c&quot;&gt;# Create the module (refresh with rm)&lt;/span&gt;
 RUN test -f go.mod || go mod init &quot;github.com/homeops-tech/slackbot&quot;
 
 # Setup SSH
 RUN git config --global url.&quot;git@github.com:&quot;.insteadOf &quot;https://github.com/&quot;
 RUN mkdir -p /root/.ssh/
 RUN ssh-keyscan github.com &amp;gt;&amp;gt; /root/.ssh/known_hosts
 
 &lt;span class=&quot;c&quot;&gt;# Download go modules&lt;/span&gt;
 RUN  --mount=type=ssh go mod download -x
 COPY . .
 
 # Build the module
 RUN --mount=type=cache,target=/root/.cache/go-build go build -ldflags=&quot;-s -w&quot; ${target}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Lets break this down, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;GOPRIVATE&lt;/code&gt; directive here is due to the fact that the repo/module we are using is private on Github.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RUN git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; url.&lt;span class=&quot;s2&quot;&gt;&quot;git@github.com:&quot;&lt;/span&gt;.insteadOf &lt;span class=&quot;s2&quot;&gt;&quot;https://github.com/&quot;&lt;/span&gt;
RUN &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /root/.ssh/
RUN ssh-keyscan github.com &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; /root/.ssh/known_hosts
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This allows use to rewrite the http url to ssh and download the known host keys during build.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This can get quite abstract but you need to authenticate inside the container to these repos. This done normally by ssh agents. see the makefile example below.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Using Buildkit&lt;/h2&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;RUN  &lt;span class=&quot;nt&quot;&gt;--mount&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;ssh go mod download &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt;
COPY &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Docker’s layer system is great for build processes as it will cache things in each layer and reuse them across builds. In the case of common libraries, especially external we don’t want that. Its just downloading the same cache over and over. Given a language like go has a compilation , this can slow down your development process. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--mount&lt;/code&gt; flag uses the new experimental BuildKit function of docker to cache just that layer across invocations.&lt;/p&gt;

&lt;p&gt;This requires a special environmental variable you can see in this Makefile example&lt;/p&gt;

&lt;p&gt;On linux you may also need to enable experimental (this is in the UI on mac)&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;$'{&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;    &quot;experimental&quot;: true&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;}'&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sudo tee&lt;/span&gt; /etc/docker/daemon.json&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;service docker restart
docker version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can reset this cache with the Make target below. Be aware that it will also get reset/wonky if you run something like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker system prune -a&lt;/code&gt; , however restarting docker will fix it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-make highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;.PHONY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;clean&lt;/span&gt;
 &lt;span class=&quot;nl&quot;&gt;clean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;err&quot;&gt;@docker&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;prune&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;--filter&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;exec.cachemount

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Makefile&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-make highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;PROJECT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;slackbot&quot;&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Build go docker image with dependencies 
&lt;/span&gt;    &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;launchctl getenv SSH_AUTH_SOCK&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DOCKER_BUILDKIT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 docker build &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--force-rm&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--ssh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;default &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--build-arg&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'./...'&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;--tag&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$(PROJECT)&lt;/span&gt;:latest &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
        .
    &lt;span class=&quot;c&quot;&gt;# Copy updated go.mod and go.sum out of container
&lt;/span&gt;    &lt;span class=&quot;nl&quot;&gt;@docker cp $(shell docker create $(PROJECT)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;latest):/src/go.mod go.mod&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;@docker cp $(shell docker create $(PROJECT)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;latest):/src/go.sum go.sum&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;.DEFAULT_GOAL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt; build

&lt;span class=&quot;nl&quot;&gt;.PHONY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2&gt;Dependencies&lt;/h2&gt;

&lt;p&gt;When using golang with other imported modules, you may create a go.mod file to pin versions of those libs. When using docker I find it useful to have that process happen inside the docker container.&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;shell docker create &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;PROJECT&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:latest&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/src/go.mod go.mod
docker &lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;shell docker create &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;PROJECT&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:latest&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/src/go.sum go.sum
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This trick means you are getting the “internal” versions that were latest when you did the download. Paired with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RUN test -f go.mod || go mod init &quot;github.com/homeops-tech/slackbot&quot;&lt;/code&gt; in your Dockerfile allows you pin version between builds. The simple example of this is on the first build, your container runs and downloads the modules and generates the file. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker cp&lt;/code&gt; commands then copies the files out of the container. On the next run, your docker container is pinned to these libraries. You can manually update them by editing the file or if you want to get the latest of all libs, simply delete the files and they will be regenerated.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I find this incredibily helpful when testing newer go versions via the Docker tag &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;FROM golang:latest&lt;/code&gt; by editing these two files you can check compatibilty without changing your local go installation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;SSH Agents&lt;/h2&gt;

&lt;p&gt;You may notice the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SSH_AUTH_SOCK&lt;/code&gt; var above is pointed towards this command &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;launchctl getenv SSH_AUTH_SOCK&lt;/code&gt;. This is essentially a supported hack on docker for mac. Unlike other platforms docker for mac is running virtually and thus it has to actually mount the ssh socket for the system inside that VM. This special path allows you to use this “hack” they built in to pass your ssh credentials via your agent to the docker container. This is very important when using golang with private repos as otherwise you would not be able to download them&lt;/p&gt;
</description>
                <pubDate>Sun, 15 Mar 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/03/15/Compile-Go-In-Docker/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/03/15/Compile-Go-In-Docker/</guid>
                
                <category>docker</category>
                
                <category>golang</category>
                
                <category>go</category>
                
                <category>make</category>
                
                <category>ssh</category>
                
                <category>macOS</category>
                
                
            </item>
        
            <item>
                <title>Configure Code Manager via Ruby</title>
                <description>&lt;p&gt;In my previous post about &lt;a href=&quot;http://www.homeops.tech/2020/01/01/Disable-Branch-Protection-Python/&quot;&gt;automating Gitlab with python&lt;/a&gt; I  showed you how you can add a webhook to Gitlabs repos dynamically. The other side of this configuration in Puppet Enterprise is configuring r10k to point towards that repo. While Gitlab has a nice python library the Puppet Enterprise classifier libraries are written in Ruby. In this quick how to I will show you the code required to configure Puppet Enterprise’s
code manager. I actually was the one who wrote this code in Puppet enterprise back in the day and reason was all about automating your PE installations end to end.&lt;/p&gt;

&lt;!--more--&gt;

&lt;table&gt;
    &lt;caption&gt;Versions tested&lt;/caption&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;th&gt;Software&lt;/th&gt;
            &lt;th&gt;Version&lt;/th&gt;
            &lt;th&gt;OS&lt;/th&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;puppet&lt;/td&gt;
            &lt;td&gt;6.19.1&lt;/td&gt;
            &lt;td&gt;Centos&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Puppet Enterprise&lt;/td&gt;
            &lt;td&gt;2019&lt;/td&gt;
            &lt;td&gt;Centos&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;Centos&lt;/td&gt;
            &lt;td&gt;7.9.2009&lt;/td&gt;
            &lt;td&gt;Centos&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;

&lt;h1&gt;Requirements&lt;/h1&gt;

&lt;p&gt;This script requires the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;puppetclassify&lt;/code&gt; gem which can be installed via&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puppetclassify&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This gem is an API wrapper around the rest calls used with the Puppet Enterprise classifier.&lt;/p&gt;

&lt;p&gt;Once installed you can modify this script to add your own Github/Gitlab/etc control repo URL.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;code_manager_config.rb&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env ruby&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'puppetclassify'&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;OpenSSL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SSL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;VERIFY_PEER&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OpenSSL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;SSL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;VERIFY_NONE&lt;/span&gt;


&lt;span class=&quot;vi&quot;&gt;@classifier_url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;https://&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:4433/classifier-api&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load_classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;auth_info&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'ca_certificate_path'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/dev/null'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;s1&quot;&gt;'token'&lt;/span&gt;               &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@classifier&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@classifier&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PuppetClassify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@classifier_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth_info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update_pe_master_r10k_remote&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;load_classifier&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@classifier&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;groups&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pe_master&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'name'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'PE Master'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pe_master&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'classes'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;puppet_enterprise_profile_master&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'puppet_enterprise::profile::master'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;puppet_enterprise_profile_master&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;puppet_enterprise_profile_master&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'code_manager_auto_configure'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'r10k_remote'&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'git@gitlab.homeops.tech:homeops-tech/control-repo.git'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'r10k_private_key'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/etc/puppetlabs/puppetserver/ssh/id-control_repo.rsa'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;s1&quot;&gt;'replication_mode'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'none'&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# I feel like this composition is overkill if this is truly a delta&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;pe_master&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'classes'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'puppet_enterprise::profile::master'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;puppet_enterprise_profile_master&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;groups&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_group&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pe_master&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;update_pe_master_r10k_remote&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can run this script with the first argument being the node classifier and the second being an RBAC Token. See &lt;a href=&quot;http://www.homeops.tech/2020/01/01/Disable-Branch-Protection-Python/&quot;&gt;automating Gitlab with python&lt;/a&gt; for an example of using the RBAC API via Python. (it does not currently have a ruby gem)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Note: that you need to ensure the Puppet server has the private key deployed at the location specified.
Also: Sorry of the use of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; here, its what the Puppet classes are named unfortunately in PE&lt;/p&gt;
&lt;/blockquote&gt;
</description>
                <pubDate>Sun, 01 Mar 2020 00:00:00 +0000</pubDate>
                <link>http://www.homeops.tech/2020/03/01/Code-Manager-Webook-Setup/</link>
                <guid isPermaLink="true">http://www.homeops.tech/2020/03/01/Code-Manager-Webook-Setup/</guid>
                
                <category>puppet</category>
                
                <category>devops</category>
                
                <category>ruby</category>
                
                <category>puppet enterprise</category>
                
                
            </item>
        
    </channel>
</rss>