<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: R. Tyler Croy</title>
    <description>The latest articles on DEV Community by R. Tyler Croy (@rtyler).</description>
    <link>https://dev.to/rtyler</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F632266%2F2c8cd9f9-d0db-4122-8754-c94f799e8ecc.jpeg</url>
      <title>DEV Community: R. Tyler Croy</title>
      <link>https://dev.to/rtyler</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rtyler"/>
    <language>en</language>
    <item>
      <title>Accessing Handlebars variables in an outer scope</title>
      <dc:creator>R. Tyler Croy</dc:creator>
      <pubDate>Thu, 08 Jul 2021 16:16:26 +0000</pubDate>
      <link>https://dev.to/rtyler/accessing-handlebars-variables-in-an-outer-scope-51eh</link>
      <guid>https://dev.to/rtyler/accessing-handlebars-variables-in-an-outer-scope-51eh</guid>
      <description>&lt;p&gt;This weekend I learned some unfamiliar behaviors with the way Handlebars handles nested variable scopes. I typically use Handlebars via the &lt;a href="https://github.com/sunng87/handlebars-rust"&gt;handlebars-rust&lt;/a&gt; implementation which aims to maintain nearly one to one compatibility with the &lt;a href="https://handlebarsjs.com/"&gt;JavaScript implementation&lt;/a&gt;. They have block scope helpers such as &lt;code&gt;#each&lt;/code&gt; and &lt;code&gt;#with&lt;/code&gt;, both of which create an inner scope for variable resolution. Unfortunately, the syntax can be quite unintuitive for accessing outer scope once in those nested scopes.&lt;/p&gt;

&lt;p&gt;Handlebars is a largely declarative templating syntax which uses curlybraces such as &lt;code&gt;{{var}}&lt;/code&gt; for variable and helper substitution. The &lt;code&gt;#each&lt;/code&gt; helper is important for loops, imagine the following data structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"repos"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"otto"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"l4bsd"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mood"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cool"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could be rendered into a list on a page via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;{% raw %}
    {{#each data.repos}}
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;{{name}}&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    {{/each}}{% endraw %}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the &lt;code&gt;#each&lt;/code&gt; block the values of the indexed object become the scope for variable resolution, such that &lt;code&gt;{{name}}&lt;/code&gt; actually refers to &lt;code&gt;data.repos[i].name&lt;/code&gt;. This presents problems when the template must refer to outer scope variables, such as &lt;code&gt;mood&lt;/code&gt;. In the Rust implementation this variable resolution can be accomplished through a path traversal style syntax such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;{% raw %}
    {{#each data.repos}}
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;{{name}} is {{../data.mood}}&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    {{/each}}{% endraw %}
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;../data.mood&lt;/code&gt; is all that's needed to refer to the variable in the outer scope of variables. Not what I expected at all, and the only reason I found it was because I found &lt;a href="https://github.com/sunng87/handlebars-rust/issues/416"&gt;an old issue&lt;/a&gt; which alluded to the syntax and gave it a try.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Increasing the density of the home lab with FreeBSD Jails</title>
      <dc:creator>R. Tyler Croy</dc:creator>
      <pubDate>Sun, 06 Jun 2021 18:01:25 +0000</pubDate>
      <link>https://dev.to/rtyler/increasing-the-density-of-the-home-lab-with-freebsd-jails-55o1</link>
      <guid>https://dev.to/rtyler/increasing-the-density-of-the-home-lab-with-freebsd-jails-55o1</guid>
      <description>&lt;p&gt;Investing the time to learn FreeBSD jails has led to a dramatic increase in the number of services I run in my "home lab." &lt;a href="https://docs.freebsd.org/en/books/handbook/jails/"&gt;Jails&lt;/a&gt;, which I have &lt;a href="///tag/freebsd.html"&gt;written about before&lt;/a&gt;, are effectively a lightweight quasi-virtualization technique which I use to create multiple software-defined networks to segment workloads. Jails have allowed me to change my "home lab" dramatically, allowing me to &lt;em&gt;reduce&lt;/em&gt; the number of machines and increase hardware utilization. For now, the days of stacking machines, dangling Raspberry Pis, or hiding laptops on the shelf are all gone. Almost all my needs have been consolidated into a single FreeBSD machine running on a 4 year old used workstation.&lt;/p&gt;

&lt;p&gt;I have attempted to consolidate the home lab before, but not with this level of success. There was the time I tried deploying a single-node Kubernetes cluster, which worked for a time until some upgrade caused the software-defined networking to break in a way I wasn't interested in debugging in my free time. Following that I tried to go "old school" and started spinning up &lt;code&gt;libvirt&lt;/code&gt;-based virtual machines which worked &lt;em&gt;well&lt;/em&gt; for a long time. The major downside of that approach is that I simply wasn't able to get much density because of the significant overhead for each virtual machine. At some point you run out of memory to commit to each VM.&lt;/p&gt;

&lt;p&gt;Converting virtual machines to FreeBSD Jails took a few hours over a weekend, and since then the &lt;strong&gt;quantity&lt;/strong&gt; of what is running has jumped dramatically. Originally I was running:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://nextcloud.com"&gt;Nextcloud&lt;/a&gt; (Apache)&lt;/li&gt;
&lt;li&gt;MySQl&lt;/li&gt;
&lt;li&gt;Gopher server&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://torproject.org/"&gt;Tor&lt;/a&gt; relay&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitea.io"&gt;Gitea&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I now &lt;em&gt;also&lt;/em&gt; run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Elasticsearch&lt;/li&gt;
&lt;li&gt;Graylog&lt;/li&gt;
&lt;li&gt;Icinga&lt;/li&gt;
&lt;li&gt;Icecast&lt;/li&gt;
&lt;li&gt;MongoDB&lt;/li&gt;
&lt;li&gt;Nginx&lt;/li&gt;
&lt;li&gt;&lt;a href="https://joinpeertube.org"&gt;Peertube&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PostgreSQL, which replaced MySQL for Nextcloud and is now running for multiple services.&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Plus some personal web apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To accomplish this, I use ZFS and Jails &lt;strong&gt;heavily&lt;/strong&gt;. All the jails run on a striped and mirrored ZFS disk array which allows for better performance and redundancy than my previous incantation. These services are low-utilization which allows them to cooperate effectively within this machine's 4 cores and 16GB of RAM.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits
&lt;/h2&gt;

&lt;p&gt;The higher utilization of this single machine, which is always-on, has a better power consumption profile than running multiple machines. More power efficiency wasn't my original motivation however, I was much more interested in some of the system administration benefits of bringing these services "under one roof." &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backups&lt;/strong&gt; are &lt;em&gt;much&lt;/em&gt; easier than before. I'm using some ZFS scripts to perform automatic snapshots on daily/weekly/monthly basis. Separately from those, I regularly push backups off-site and that's trivial because at the "host" machine level, not the jail level, I can access all the filesystems at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security&lt;/strong&gt; is much easier as well since Jails are obviously providing a level of isolation. On top of that, I am using the &lt;code&gt;vnet&lt;/code&gt; functionality in FreeBSD to provide additional network segmentation, something I never did with physical or virtual machines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Management&lt;/strong&gt; is pretty straightforward with all these services running in Jails. I typically do all my administration from the host rather than the jail level. As such I can pretty easily shuffle configuration files around.  Unfortunately to date I haven't found a good configuration management tool, including my own &lt;a href="https://github.com/rtyler/zap"&gt;tinkering&lt;/a&gt; that provides a Jails-aware set of tools for more automation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Downsides
&lt;/h2&gt;

&lt;p&gt;The most notable downside to this approach is that a hardware failure &lt;em&gt;could&lt;/em&gt; take me offline for a bit. These services are all dependent on a single power supply (PSU) and CPU. As such a failure of either would require me to keep all these services offline until that part could be replaced. For a home lab setup, I'm not expecting to support a specific SLA, so I'm quite comfortable with this risk.&lt;/p&gt;

&lt;p&gt;I can imagine some security arguments that could be made, but frankly I think this Jails approach is &lt;em&gt;much&lt;/em&gt; better secured than my previous home lab setups.&lt;/p&gt;




&lt;p&gt;At present this machine has just under 10GB of RAM in use and a load average that floats between 1.0 and 2.0. Despite all the services that are running, it still uses &lt;em&gt;less&lt;/em&gt; than my workstation with a few browsers open. To deploy your own "home lab" set up in this way you absolutely &lt;em&gt;do not&lt;/em&gt; need a high powered machine. I would argue that a ZFS-based disk array is likely more important, after all most home lab tasks, that aren't video-encoding, tend to be more disk I/O heavy rather than memory/CPU heavy.&lt;/p&gt;

&lt;p&gt;This path isn't quite entry-level simple, but if you have some systems administration experience, I think &lt;a href="https://freebsd.org"&gt;FreeBSD&lt;/a&gt; with ZFS and Jails is worth considering for your home or office lab.&lt;/p&gt;

</description>
      <category>freebsd</category>
      <category>jails</category>
    </item>
    <item>
      <title>Converting XML to JSON in Rust</title>
      <dc:creator>R. Tyler Croy</dc:creator>
      <pubDate>Sun, 23 May 2021 17:43:34 +0000</pubDate>
      <link>https://dev.to/rtyler/converting-xml-to-json-in-rust-1mnp</link>
      <guid>https://dev.to/rtyler/converting-xml-to-json-in-rust-1mnp</guid>
      <description>&lt;p&gt;I generally default to using JSON for data interchange but there are still a myriad of formats of XML out there, for which I have created the &lt;a href="https://crates.io/crates/xmltojson"&gt;xmltojson&lt;/a&gt; crate. I originally wrote this one night to help me get an XML dataset into JSON so that I could use &lt;a href="https://postgresql.org"&gt;PostgreSQL's&lt;/a&gt; &lt;code&gt;JSONB&lt;/code&gt; column type, but I only recently published it to &lt;a href="https://crates.io"&gt;crates.io&lt;/a&gt; since it may be useful for others.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cargo.toml&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[dependencies]&lt;/span&gt;
&lt;span class="py"&gt;xmltojson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;xmltojson&lt;/code&gt; crate implements &lt;a href="https://goessner.net/download/prj/jsonxml/"&gt;Stefan Goessner’s xml2json&lt;/a&gt; which results in a fairly straightforward conversion of XML data structure into JSON. Take the following XML for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ol&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"xoxo"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;Subject 1
        &lt;span class="nt"&gt;&amp;lt;ol&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;subpoint a&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;subpoint b&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;span&amp;gt;&lt;/span&gt;Subject 2&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ol&lt;/span&gt; &lt;span class="na"&gt;compact=&lt;/span&gt;&lt;span class="s"&gt;"compact"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;subpoint c&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;subpoint d&lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ol&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This XML structured will be rapidly converted into the following JSON, with&lt;br&gt;
attributes and children encoded into the structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"@class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"xoxo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"li"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"#text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Subject 1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"ol"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"li"&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"subpoint a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"subpoint b"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"span"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"Subject 2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"ol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"@compact"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"compact"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"li"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"subpoint c"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="s2"&gt;"subpoint d"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are some oddities with the JSON encoding of XML, particularly around CDATA, but overall I have been quite pleased turning XML into JSON which I can more easily query with &lt;code&gt;jq&lt;/code&gt;, PostgreSQL, or even ingest into Elasticsearch.&lt;/p&gt;

&lt;p&gt;If you happen to find any bugs, please submit pull requests &lt;a href="https://github.com/rtyler/xmltojson"&gt;on GitHub&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>json</category>
      <category>xml</category>
    </item>
    <item>
      <title>Dynamically forwarding ports within an existing SSH connection</title>
      <dc:creator>R. Tyler Croy</dc:creator>
      <pubDate>Sun, 16 May 2021 20:50:45 +0000</pubDate>
      <link>https://dev.to/rtyler/dynamically-forwarding-ports-within-an-existing-ssh-connection-nj4</link>
      <guid>https://dev.to/rtyler/dynamically-forwarding-ports-within-an-existing-ssh-connection-nj4</guid>
      <description>&lt;p&gt;Working over SSH on a big beefy remote machine is a great way to extend the life of any laptop, but presents challenges when developing network-based services. Fortunately OpenSSH has a "port forwarding" feature which has been around for a number of years. Port forwarding allows the user to tunnel a port from the remote machine back to their local machine, in essence allowing you to access a remote service bound to port 8000 on your own &lt;code&gt;localhost:8000&lt;/code&gt;. When I first learned about this, I would fiddle around with my &lt;code&gt;ssh&lt;/code&gt; invocations or hardcode a list of potential ports forwarded in my &lt;code&gt;~/.ssh/config&lt;/code&gt;.  If I was working on a new service that needed a port not yet forwarded, I would disconnect, add it to the list of ports in my &lt;code&gt;config&lt;/code&gt; file, and then reconnect. That was until my pal &lt;a href="https://github.com/nibalizer"&gt;nibz (nibalizer)&lt;/a&gt; showed me how to &lt;em&gt;dynamically&lt;/em&gt; add port forwards to an already existing session.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.openssh.com/"&gt;OpenSSH&lt;/a&gt; provides a number of &lt;strong&gt;escape characters&lt;/strong&gt; that can be used on a running connection, one of these is &lt;code&gt;~C&lt;/code&gt; which will open up a little command line interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯
ssh&amp;gt; ?
Commands:
      -L[bind_address:]port:host:hostport    Request local forward
      -R[bind_address:]port:host:hostport    Request remote forward
      -D[bind_address:]port                  Request dynamic forward
      -KL[bind_address:]port                 Cancel local forward
      -KR[bind_address:]port                 Cancel remote forward
      -KD[bind_address:]port                 Cancel dynamic forward
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this simple command line you can add or remove local, remote, and dynamic port forwards! Pretty snazzy! When I was first learning how to use these escape characters I had a difficult time getting the key-combination correct, frequently I would somehow screw it up and just send &lt;code&gt;~C&lt;/code&gt; to the shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;❯ ~C
zsh: no such user or named directory: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The approach that I have found most reliable is to hold my left shift key down while I hit &lt;code&gt;~&lt;/code&gt; and &lt;code&gt;C&lt;/code&gt; in sequence. In essence, my left pinky finger keeps shift depressed while my middle finger and then my pointer finger consecutively hit the two keys. I share this because when I first started to use these escape sequences I could never get the timing/cadence correct the first time and it felt like I was wasting more time than it would take to just disconnect and&lt;br&gt;
reconnect.&lt;/p&gt;

&lt;p&gt;Another tip is to make sure you have detached from any active &lt;code&gt;tmux&lt;/code&gt; sessions, as &lt;code&gt;tmux&lt;/code&gt; has it's own escape sequences and key bindings that you likely want to avoid triggering.&lt;/p&gt;

&lt;p&gt;Once you get the hang of it, you can dynamically allocate new ports for whatever service you're developing and then easily use your local browser/client to access the service under development. Much better!&lt;/p&gt;

&lt;p&gt;For more escape characters, refer to the &lt;code&gt;ssh(1)&lt;/code&gt; manpage via &lt;code&gt;man ssh&lt;/code&gt; which has a section dedicated to these magic key combos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ESCAPE CHARACTERS
     When a pseudo-terminal has been requested, ssh supports a number of functions through the use of an escape character.

     A single tilde character can be sent as ~~ or by following the tilde by a character other than those described below.  The escape
     character must always follow a newline to be interpreted as special.  The escape character can be changed in configuration files us-
     ing the EscapeChar configuration directive or on the command line by the -e option.

     The supported escapes (assuming the default ‘~’) are:

     ~.      Disconnect.

     ~^Z     Background ssh.

     ~#      List forwarded connections.

     ~&amp;amp;      Background ssh at logout when waiting for forwarded connection / X11 sessions to terminate.

     ~?      Display a list of escape characters.

     ~B      Send a BREAK to the remote system (only useful if the peer supports it).

     ~C      Open command line.  Currently this allows the addition of port forwardings using the -L, -R and -D options (see above).  It
             also allows the cancellation of existing port-forwardings with -KL[bind_address:]port for local, -KR[bind_address:]port for
             remote and -KD[bind_address:]port for dynamic port-forwardings.  !command allows the user to execute a local command if the
             PermitLocalCommand option is enabled in ssh_config(5).  Basic help is available, using the -h option.

     ~R      Request rekeying of the connection (only useful if the peer supports it).

     ~V      Decrease the verbosity (LogLevel) when errors are being written to stderr.

     ~v      Increase the verbosity (LogLevel) when errors are being written to stderr.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>openssh</category>
      <category>linux</category>
    </item>
    <item>
      <title>Generating pre-signed S3 URLs in Rust</title>
      <dc:creator>R. Tyler Croy</dc:creator>
      <pubDate>Sun, 16 May 2021 14:57:12 +0000</pubDate>
      <link>https://dev.to/rtyler/generating-pre-signed-s3-urls-in-rust-27gd</link>
      <guid>https://dev.to/rtyler/generating-pre-signed-s3-urls-in-rust-27gd</guid>
      <description>&lt;p&gt;Creating Pre-signed S3 URLs in Rust took me a little more brainpower than I had anticipated, so I thought I would share how to generate them using &lt;a href="https://rusoto.github.io/"&gt;Rusoto&lt;/a&gt;.  &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/userguide/ShareObjectPreSignedURL.html"&gt;Pre-signed URLs&lt;/a&gt; allow the creation of purpose built URLs for fetching or uploading objects to S3, and can be especially useful when granting access to S3 objects to mobile or web clients. In my use-case, I wanted the clients of my web service to be able to access some specific objects from a bucket.&lt;/p&gt;

&lt;p&gt;Rusoto supports the creation of pre-signed URLs via the &lt;a href="https://docs.rs/rusoto_s3/0.46.0/rusoto_s3/util/trait.PreSignedRequest.html"&gt;PreSignedRequest&lt;/a&gt; which is implemented for &lt;code&gt;GetObjectRequest&lt;/code&gt;, &lt;code&gt;PutObjectRequest&lt;/code&gt;, etc. The trait exposes a simple method &lt;code&gt;get_presigned_url&lt;/code&gt; which returns a String with all the query parameters to allow for a pre-signed request. &lt;em&gt;Unfortunately&lt;/em&gt; however, these &lt;code&gt;GetObjectRequest&lt;/code&gt; structs don't really blend easily with an existing &lt;a href="https://docs.rs/rusoto_s3/0.46.0/rusoto_s3/struct.S3Client.html"&gt;S3Client&lt;/a&gt; and need to be constructed with the appropriate region and credentials whenever you want to use them.&lt;/p&gt;

&lt;p&gt;Starting with the region, I re-use some code we have in &lt;a href="https://github.com/delta-io/delta-rs"&gt;delta-rs&lt;/a&gt; for identifying the region in a way that allows testing with localstack or minio via the &lt;code&gt;AWS_ENDPOINT_URL&lt;/code&gt; environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rusoto_core&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;region&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS_ENDPOINT_URL"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Custom&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS_REGION"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.unwrap_or_else&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="mi"&gt;_&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="s"&gt;"custom"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For most users, this code doesn't really do much, but if you've got a custom &lt;code&gt;AWS_REGION&lt;/code&gt; or &lt;code&gt;AWS_ENDPOINT_URL&lt;/code&gt;, you need to properly construct a custom &lt;code&gt;Region&lt;/code&gt; in order for Rusoto to work.&lt;/p&gt;

&lt;p&gt;The next important argument that &lt;code&gt;get_presigned_url&lt;/code&gt; requires is an &lt;code&gt;AwsCredentials&lt;/code&gt; provider, which I was originally quite worried about hacking into place. Once again I went looking at the delta-rs codebase for inspiration and noticed our use of &lt;code&gt;ChainProvider&lt;/code&gt; which tries its best to find the right AWS credentials given the user's environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rusoto_credential&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ChainProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rusoto_credential&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ProvideAwsCredentials&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ChainProvider&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="nf"&gt;.credentials&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With those two pieces in place, I could finally construct the URL!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rusoto_s3&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;GetObjectRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rusoto_s3&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;util&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;PreSignedRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PreSignedRequestOption&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PreSignedRequestOption&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;expires_in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetObjectRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"my-bucket"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"secret.txt"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="nn"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="nf"&gt;.get_presigned_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;region&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, in your application you might find the structure of managing a shared credentials provider or region to change the structure of the code. However you manage them, as long as you can plug a reference to either into the &lt;code&gt;get_presigned_url&lt;/code&gt; function, you can generate useful pre-signed URLs for S3, &lt;a href="https://min.io"&gt;Minio&lt;/a&gt;, etc.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
