<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title><![CDATA[Piotr Kalinowski]]></title><description><![CDATA[Notes on a journey through the cyberspace]]></description><link>https://piotrkalinowski.com/</link><atom:link href="https://piotrkalinowski.com/rss.xml" rel="self" type="application/rss+xml"/><item><title><![CDATA[Filling drive to the max with various Chia plot sizes]]></title><description><![CDATA[First note I'm sharing from "How to waste less with Chia" notebook: finding combination of elements from different sets occupying as much space as possible]]></description><link>https://piotrkalinowski.com/note/filling-drive-with-chia-plots-to-the-max/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/filling-drive-with-chia-plots-to-the-max/</guid><category><![CDATA[python]]></category><pubDate>Sun, 24 Oct 2021 20:31:36 GMT</pubDate><content:encoded><![CDATA[<p>My 70TB solo Chia farm reminded about itself after three months by producing 2 blocks, with about two weeks inbetween. This was an impulse for me to update it with things that were introduced during this time. Biggest change was pooling so I have created NFT, joined space.pool and started plotting. I was curious how it is to work with bigger files so I have decided to add k33 and k34 plots to my farm. K35 are IMHO too uncomfortable at the moment and there’s higher chance that with time e.g. bad block/sector will appear and it will be impossible to move such a big file to other device. I ended with mix of 103GB, 209GB and 430GB files and since these filesizes don’t increase geometrically I thought that it would be wise to fill space as efficiently as I can.</p>
<p>After few weeks I have already plotted big enough sample of different k-sizes so last thing left was finding biggest files from each category. I have a single harvester that has all the drives pooled with mergerfs so the fastest way was to list all files sorting them by size with <code>ls -lS --block-size=M /mnt/chia/farm</code> and pick largest ones (rounding them a bit) manually. My google-fu failed me this time and not being able to find efficient and satysfying solution online I came up with this script:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">from</span><span style="color:#E1E4E8"> collections </span><span style="color:#F97583">import</span><span style="color:#E1E4E8"> Counter</span></span>
<span class="line"></span>
<span class="line"><span style="color:#6A737D">#disk_space = 4658 # G</span></span>
<span class="line"><span style="color:#6A737D">#plot_sizes = {'k34': 430, 'k33': 209, 'k32': 102}</span></span>
<span class="line"><span style="color:#E1E4E8">disk_space </span><span style="color:#F97583">=</span><span style="color:#79B8FF"> 4767650</span><span style="color:#6A737D"> # M</span></span>
<span class="line"><span style="color:#E1E4E8">plot_sizes </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> {</span><span style="color:#9ECBFF">'k34'</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">440220</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">'k33'</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">213900</span><span style="color:#E1E4E8">, </span><span style="color:#9ECBFF">'k32'</span><span style="color:#E1E4E8">: </span><span style="color:#79B8FF">103900</span><span style="color:#E1E4E8">}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">res </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> {}</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">def</span><span style="color:#B392F0"> get_combinations</span><span style="color:#E1E4E8">(total_size, history, last_size):</span></span>
<span class="line"><span style="color:#F97583">  for</span><span style="color:#E1E4E8"> plot_size, file_size </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> plot_sizes.items():</span></span>
<span class="line"><span style="color:#F97583">    if</span><span style="color:#E1E4E8"> file_size </span><span style="color:#F97583">&#x3C;=</span><span style="color:#E1E4E8"> last_size:</span></span>
<span class="line"><span style="color:#F97583">       if</span><span style="color:#E1E4E8"> total_size </span><span style="color:#F97583">+</span><span style="color:#E1E4E8"> file_size </span><span style="color:#F97583">&#x3C;=</span><span style="color:#E1E4E8"> disk_space:</span></span>
<span class="line"><span style="color:#E1E4E8">          get_combinations(total_size </span><span style="color:#F97583">+</span><span style="color:#E1E4E8"> file_size, history </span><span style="color:#F97583">+</span><span style="color:#E1E4E8"> [plot_size], file_size)</span></span>
<span class="line"><span style="color:#F97583">       else</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">          free_space </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> disk_space </span><span style="color:#F97583">-</span><span style="color:#E1E4E8"> total_size</span></span>
<span class="line"><span style="color:#F97583">          if</span><span style="color:#E1E4E8"> free_space </span><span style="color:#F97583">&#x3C;</span><span style="color:#79B8FF"> min</span><span style="color:#E1E4E8">(plot_sizes.values()):</span></span>
<span class="line"><span style="color:#F97583">            if</span><span style="color:#79B8FF"> str</span><span style="color:#E1E4E8">(free_space) </span><span style="color:#F97583">not</span><span style="color:#F97583"> in</span><span style="color:#E1E4E8"> res:</span></span>
<span class="line"><span style="color:#E1E4E8">              res[</span><span style="color:#79B8FF">str</span><span style="color:#E1E4E8">(free_space)] </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> []</span></span>
<span class="line"><span style="color:#E1E4E8">            res[</span><span style="color:#79B8FF">str</span><span style="color:#E1E4E8">(free_space)].append(</span><span style="color:#79B8FF">sorted</span><span style="color:#E1E4E8">(Counter(history).items(),</span><span style="color:#FFAB70">reverse</span><span style="color:#F97583"> =</span><span style="color:#79B8FF"> True</span><span style="color:#E1E4E8">))</span></span>
<span class="line"><span style="color:#F97583">            break</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">get_combinations(</span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">, [], plot_sizes[</span><span style="color:#9ECBFF">'k34'</span><span style="color:#E1E4E8">])</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">sortedKeys </span><span style="color:#F97583">=</span><span style="color:#79B8FF"> list</span><span style="color:#E1E4E8">(res.keys())</span></span>
<span class="line"><span style="color:#E1E4E8">sortedKeys.sort(</span><span style="color:#FFAB70">key</span><span style="color:#F97583">=</span><span style="color:#79B8FF">int</span><span style="color:#E1E4E8">)</span></span>
<span class="line"><span style="color:#F97583">for</span><span style="color:#E1E4E8"> key </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> sortedKeys:</span></span>
<span class="line"><span style="color:#79B8FF">    print</span><span style="color:#E1E4E8">(key, res[key])</span></span></code></pre>
<p>And here is the output:</p>
<p><img src="https://piotrkalinowski.com/note/filling-drive-with-chia-plots-to-the-max/plotplan-result-1.png" alt=""></p>
<p>The outcome was that instead of losing 90GB from each 5TB disk, like it was with OG non-NFT plots, I’m leaving max few gigs free.</p>]]></content:encoded></item><item><title><![CDATA[Elastic Stack with SQL Server]]></title><description><![CDATA[Easy way to sync Elasticsearch index with practically any DMBS, in this case MSSQL]]></description><link>https://piotrkalinowski.com/note/elasticsearch-with-ms-sql/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/elasticsearch-with-ms-sql/</guid><category><![CDATA[elasticsearch]]></category><pubDate>Sat, 24 Jul 2021 15:56:32 GMT</pubDate><content:encoded><![CDATA[<p>IMHO simplest way to populate Elasticsearch with data from DMBS, assuming there is a driver for JDBC, is to use Logstash. Of course it’s nowhere near to proper sync that should handle  not only inserts and updates but deletes as well but in most cases this will be enough for prototyping, testing or learning concepts.</p>
<p>These instructions are for Microsoft SQL Server but same can be done easily with other DBMSes like MySQL or PostgreSQL. I’m assuming Elasticsearch is already installed somewhere. If it’s listening on localhost head to /etc/elasticsearch/elasticsearch.yml and add:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="plaintext"><code><span class="line"><span>network.host: _site_</span></span>
<span class="line"><span>discovery.type: single-node</span></span></code></pre>
<p>Restart elastic instance. Now lets install Logstash</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">curl</span><span style="color:#79B8FF"> -fsSL</span><span style="color:#9ECBFF"> https://artifacts.elastic.co/GPG-KEY-elasticsearch</span><span style="color:#F97583"> |</span><span style="color:#B392F0"> apt-key</span><span style="color:#9ECBFF"> add</span><span style="color:#9ECBFF"> -</span></span>
<span class="line"><span style="color:#79B8FF">echo</span><span style="color:#9ECBFF"> "deb https://artifacts.elastic.co/packages/7.x/apt stable main"</span><span style="color:#F97583"> |</span><span style="color:#B392F0"> tee</span><span style="color:#79B8FF"> -a</span><span style="color:#9ECBFF"> /etc/apt/sources.list.d/elastic-7.x.list</span></span>
<span class="line"><span style="color:#B392F0">apt</span><span style="color:#9ECBFF"> update</span></span>
<span class="line"><span style="color:#B392F0">apt</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> logstash</span></span></code></pre>
<p>To be able to talk with SQL Server we will need to use appropriate JDBC driver. Most recent version available at time of writing is 9.2 and supports SQL Server versions starting from 2012 and newer. Logstash is currently packaged with Java 11.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="plaintext"><code><span class="line"><span>mkdir -p /opt/sqljdbc_9.2/enu/</span></span>
<span class="line"><span>wget https://github.com/microsoft/mssql-jdbc/releases/download/v9.2.1/mssql-jdbc-9.2.1.jre11.jar -P /opt/sqljdbc_9.2/enu/</span></span></code></pre>
<p>Logstash allows to select column that will be used to sync from SQL Server only inserted/updated records, in this case it’s “updated_at”. By default this value is stored in ~/.logstash_jdbc_last_run. Location of this file can be changed using last_run_metadata_path variable - I like to have all things related to particular service stored in one place so lets put it in /var/lib/logstash/jdbc_last_runs/ directory (should be taken from path.data)</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">mkdir</span><span style="color:#9ECBFF"> /var/lib/logstash/jdbc_last_runs</span></span></code></pre>
<p>Here’s sample config file:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="plaintext"><code><span class="line"><span>input {</span></span>
<span class="line"><span>    jdbc {</span></span>
<span class="line"><span>        jdbc_connection_string => "jdbc:sqlserver://192.168.1.124\MSSQLSERVER;database=Test;user=sa;password=Passwd123"</span></span>
<span class="line"><span>        jdbc_user => nil</span></span>
<span class="line"><span>        jdbc_driver_library => "/opt/sqljdbc_9.2/enu/mssql-jdbc-9.2.1.jre11.jar"</span></span>
<span class="line"><span>        jdbc_driver_class => "com.microsoft.sqlserver.jdbc.SQLServerDriver"</span></span>
<span class="line"><span></span></span>
<span class="line"><span>        statement => "SELECT * FROM dbo.sampletable WHERE updated_at >= :sql_last_value"</span></span>
<span class="line"><span>        # statement_filepath</span></span>
<span class="line"><span>        last_run_metadata_path => "/var/lib/logstash/jdbc_last_runs/sampletable"</span></span>
<span class="line"><span>        use_column_value => true</span></span>
<span class="line"><span>        tracking_column => "@timestamp"</span></span>
<span class="line"><span>        shedule => "0 * * * *"</span></span>
<span class="line"><span>    }</span></span>
<span class="line"><span>}</span></span>
<span class="line"><span></span></span>
<span class="line"><span>output {</span></span>
<span class="line"><span>    elasticsearch {</span></span>
<span class="line"><span>        hosts => ["192.168.1.121:9200"]</span></span>
<span class="line"><span>        index => "test"</span></span>
<span class="line"><span>    }</span></span>
<span class="line"><span>    stdout { codec => rubydebug }</span></span>
<span class="line"><span>}</span></span></code></pre>
<p><em>/etc/logstash/conf.d/sampletable.conf</em></p>
<p>If there is no <em>id</em> column in our table we should add it to update rows that we have already fetched instead of inserting them again. Something like “SELECT [table id] as id, * FROM…” should do the job.  Now lets test our settings doing initial import:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">/usr/share/logstash/bin/logstash</span><span style="color:#79B8FF"> -f</span><span style="color:#9ECBFF"> /etc/logstash/conf.d/sampletable.conf</span></span></code></pre>
<p>If there were no errors we should have our data in Elasticsearch.</p>
<p>Useful links</p>
<blockquote>
<p><a href="https://docs.microsoft.com/en-us/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server">https://docs.microsoft.com/en-us/sql/connect/jdbc/download-microsoft-jdbc-driver-for-sql-server</a>
<a href="https://docs.microsoft.com/en-us/sql/connect/jdbc/microsoft-jdbc-driver-for-sql-server-support-matrix">https://docs.microsoft.com/en-us/sql/connect/jdbc/microsoft-jdbc-driver-for-sql-server-support-matrix</a></p>
</blockquote>]]></content:encoded></item><item><title><![CDATA[Simple OpenVPN site to site bridge]]></title><description><![CDATA[Bridging LAN with OVH private network (vRack) using OpenVPN TAP adapters]]></description><link>https://piotrkalinowski.com/note/simple-site-to-site-openvpn-bridge/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/simple-site-to-site-openvpn-bridge/</guid><category><![CDATA[vpn]]></category><category><![CDATA[ovh]]></category><pubDate>Mon, 31 May 2021 14:44:26 GMT</pubDate><content:encoded><![CDATA[<p>A while ago I’ve upgraded my WAN to 1gbps/300mbps FTTH and because of this I have only 10ms delay to OVH Warsaw DC (previously ~40ms). This gave me possibility to reliably bridge my lab with vRack, and this way I could finally get rid of dedicated server and host everything by myself. Result (ping host in my lab via tunnel with public OVH IP address, gateway in OVH Warsaw DC, iperf3 to lab via tunnel, iperf3 from lab via tunnel):</p>
<p><img src="https://piotrkalinowski.com/note/simple-site-to-site-openvpn-bridge/image-5.png" alt=""></p>
<p>Recently OVH upgraded their Sandbox PI line and renamed it to Discovery:</p>
<p><img src="https://piotrkalinowski.com/note/simple-site-to-site-openvpn-bridge/image-6.png" alt=""></p>
<p>Besides making price bigger they have provided us with option to get connections faster than 100mbps and now middle variant is perfect fit for my WAN.</p>
<p>After some testing I decided to use OpenVPN under Ubuntu on both sides - OVH d2-4 as VPN server and LXC container as VPN client. Installation is quite straightforward, so on both ends:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">apt</span><span style="color:#9ECBFF"> install</span><span style="color:#9ECBFF"> openvpn</span><span style="color:#9ECBFF"> bridge-utils</span></span></code></pre>
<p>Since on this tunnel I don’t want more traffic than necessary, I will have only one client connecting to server. Simple static key auth will be enough:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">openvpn</span><span style="color:#79B8FF"> --genkey</span><span style="color:#79B8FF"> --secret</span><span style="color:#9ECBFF"> /etc/openvpn/static.key</span></span>
<span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> /etc/openvpn/server.conf</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">#verb 4</span></span>
<span class="line"><span style="color:#9ECBFF">dev tap0</span></span>
<span class="line"><span style="color:#9ECBFF">dev-type tap</span></span>
<span class="line"><span style="color:#9ECBFF">script-security 3</span></span>
<span class="line"><span style="color:#9ECBFF">daemon</span></span>
<span class="line"><span style="color:#9ECBFF">keepalive 10 60</span></span>
<span class="line"><span style="color:#9ECBFF">ping-timer-rem</span></span>
<span class="line"><span style="color:#9ECBFF">persist-tun</span></span>
<span class="line"><span style="color:#9ECBFF">persist-key</span></span>
<span class="line"><span style="color:#9ECBFF">proto udp</span></span>
<span class="line"><span style="color:#9ECBFF">cipher AES-128-CBC</span></span>
<span class="line"><span style="color:#9ECBFF">auth SHA1</span></span>
<span class="line"><span style="color:#9ECBFF">lport 1194</span></span>
<span class="line"><span style="color:#9ECBFF">up server.sh</span></span>
<span class="line"><span style="color:#9ECBFF">secret static.key</span></span>
<span class="line"><span style="color:#9ECBFF">log /var/log/openvpn/server.log</span></span>
<span class="line"><span style="color:#9ECBFF">status /var/log/openvpn/server.status</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<p>We need to bridge interface in vRack (private network) with TAP adapter. Easiest and in this case probably cleanest way is to let OpenVPN do it:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> /etc/openvpn/server.sh</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color:#9ECBFF">ip link add br0 type bridge</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set tap0 master br0</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set ens4 master br0</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set br0 up</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set tap0 up</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span>
<span class="line"><span style="color:#B392F0">chmod</span><span style="color:#9ECBFF"> u+x</span><span style="color:#9ECBFF"> /etc/openvpn/server.sh</span></span></code></pre>
<p>Now we should configure firewalls (e.g. UFW and OVH firewall) to reflect our infrastructure, e.g. filtering with static list of IPs allowed to talk with port 1194. Finally we can start OpenVPN server:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> enable</span><span style="color:#9ECBFF"> openvpn@server</span><span style="color:#79B8FF"> --now</span></span>
<span class="line"><span style="color:#B392F0">tail</span><span style="color:#9ECBFF"> /var/log/openvpn/server.log</span></span></code></pre>
<p>Now lets configure client, assuming it is using vpn.yourserver.com subdomain:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> /etc/openvpn/client.conf</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">dev tap0</span></span>
<span class="line"><span style="color:#9ECBFF">persist-tun</span></span>
<span class="line"><span style="color:#9ECBFF">persist-key</span></span>
<span class="line"><span style="color:#9ECBFF">cipher AES-128-CBC</span></span>
<span class="line"><span style="color:#9ECBFF">auth SHA1</span></span>
<span class="line"><span style="color:#9ECBFF">script-security 3</span></span>
<span class="line"><span style="color:#9ECBFF">up client.sh</span></span>
<span class="line"><span style="color:#9ECBFF">remote vpn.yourserver.com 1194 udp</span></span>
<span class="line"><span style="color:#9ECBFF">secret static.key</span></span>
<span class="line"><span style="color:#9ECBFF">log /var/log/openvpn/client.log</span></span>
<span class="line"><span style="color:#9ECBFF">status /var/log/openvpn/client.status</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> /etc/openvpn/client.sh</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">#!/bin/bash</span></span>
<span class="line"></span>
<span class="line"><span style="color:#9ECBFF">ip link add br0 type bridge</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set tap0 master br0</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set ens19 master br0</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set br0 up</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set tap0 up</span></span>
<span class="line"><span style="color:#9ECBFF">ip link set ens19 up</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span>
<span class="line"><span style="color:#B392F0">chmod</span><span style="color:#9ECBFF"> u+x</span><span style="color:#9ECBFF"> /etc/openvpn/client.sh</span></span>
<span class="line"></span>
<span class="line"><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> enable</span><span style="color:#9ECBFF"> openvpn@client</span><span style="color:#79B8FF"> --now</span></span>
<span class="line"><span style="color:#B392F0">tail</span><span style="color:#9ECBFF"> /var/log/openvpn/client.log</span></span></code></pre>
<p>Similar config may be used for other scenarios, like for example <strong>connecting OVH vRack to dedicated server from different provider</strong>.</p>
<p>Probably some of our packets won’t be forwarded because of their size, we should fragment them then. Easiest way to find max packet size is to ping starting from size we know that should be passed with default MTU in our network, usually it’s 1500 - so this gives 1500 bytes (Ethernet MTU) - 20 byte (IP header) - 8 byte (ICMP header) = 1472 bytes max . Lets start with this number and lower it on every retry till we will receive answer. From Windows:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="plaintext"><code><span class="line"><span>ping -f -n 1 -l 1472 host.behind.vpn </span></span></code></pre>
<p>Or from Linux:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ping</span><span style="color:#79B8FF"> -M</span><span style="color:#9ECBFF"> do</span><span style="color:#79B8FF"> -c</span><span style="color:#79B8FF"> 1</span><span style="color:#79B8FF"> -s</span><span style="color:#79B8FF"> 1472</span><span style="color:#9ECBFF"> host.behind.vpn</span><span style="color:#E1E4E8"> </span></span></code></pre>
<p>In my case it was AFAIR 1350 so we have to both config files (this setting can’t be pushed), client and server:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">fragment</span><span style="color:#79B8FF"> 1350</span></span></code></pre>
<p>Other thing we might want is tunneling data between from all vlans, to do this add to both scripts started by OpenVPN (assuming we already have VLAN-aware bridge):</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ip</span><span style="color:#9ECBFF"> link</span><span style="color:#9ECBFF"> set</span><span style="color:#9ECBFF"> tap0</span><span style="color:#9ECBFF"> promisc</span><span style="color:#9ECBFF"> on</span></span>
<span class="line"><span style="color:#B392F0">bridge</span><span style="color:#9ECBFF"> vlan</span><span style="color:#9ECBFF"> add</span><span style="color:#9ECBFF"> vid</span><span style="color:#9ECBFF"> 2-4094</span><span style="color:#9ECBFF"> dev</span><span style="color:#9ECBFF"> tap0</span></span></code></pre>]]></content:encoded></item><item><title><![CDATA[Additional network configuration of Ubuntu container in PVE]]></title><description><![CDATA[Permanent configuration of network interfaces in systemd-networkd based containers]]></description><link>https://piotrkalinowski.com/note/static-routes-in-ubuntu-20-04-lxc/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/static-routes-in-ubuntu-20-04-lxc/</guid><category><![CDATA[pve]]></category><pubDate>Mon, 29 Mar 2021 00:26:01 GMT</pubDate><content:encoded><![CDATA[<p>In LXC containers spawned under Proxmox Virtual Environment I often need to <strong>add another IP address</strong> or define some <strong>additional static routes going through secondary interface</strong> that should use different gateway. Usually this can be done by adding few lines to e.g. /etc/systemd/network/eth0.network but after restart of container PVE would overwrite it. Luckily networkd makes it easy to extend config by creating file in  /etc/systemd/network/eth0.network.d folder.</p>
<p>I’ll be using below configuration in my examples:</p>
<p><img src="https://piotrkalinowski.com/note/static-routes-in-ubuntu-20-04-lxc/image.png" alt=""></p>
<p>To add additional IP addresses to interface, we can create e.g. /etc/systemd/network/eth0.network.d/ips.conf file:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="plaintext"><code><span class="line"><span>[Network]</span></span>
<span class="line"><span>Address=1.2.3.4/29</span></span>
<span class="line"><span>Address=5.6.7.8/27</span></span></code></pre>
<p>Now just restart networkd and check if everything went as we’ve planned</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> systemd-networkd</span><span style="color:#E1E4E8"> &#x26;&#x26; </span><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> status</span><span style="color:#9ECBFF"> systemd-networkd</span><span style="color:#E1E4E8"> &#x26;&#x26; </span><span style="color:#B392F0">ip</span><span style="color:#9ECBFF"> a</span></span></code></pre>
<p>Another case where such functionality is helpful is when we want to add some static routes - lets say we have two interfaces: eth0 with public ip and isp gateway and eth1 for private/internal network with its own router for, inter alia, vpn access. Because traffic from all potential private networks will go only through this second interface lets configure them in /etc/systemd/network/eth1.network.d/static.conf</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="plaintext"><code><span class="line"><span>[Route]</span></span>
<span class="line"><span>Destination=10.0.0.0/8</span></span>
<span class="line"><span>GatewayOnLink=true</span></span>
<span class="line"><span>Gateway=10.7.17.1</span></span>
<span class="line"><span></span></span>
<span class="line"><span>[Route]</span></span>
<span class="line"><span>Destination=172.16.0.0/12</span></span>
<span class="line"><span>GatewayOnLink=true</span></span>
<span class="line"><span>Gateway=10.7.17.1</span></span>
<span class="line"><span></span></span>
<span class="line"><span>[Route]</span></span>
<span class="line"><span>Destination=192.168.0.0/16</span></span>
<span class="line"><span>GatewayOnLink=true</span></span>
<span class="line"><span>Gateway=10.7.17.1</span></span></code></pre>
<p>Apply new settings, show potential errors and display current routes:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> restart</span><span style="color:#9ECBFF"> systemd-networkd</span><span style="color:#E1E4E8"> &#x26;&#x26; </span><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> status</span><span style="color:#9ECBFF"> systemd-networkd</span><span style="color:#E1E4E8"> &#x26;&#x26; </span><span style="color:#B392F0">ip</span><span style="color:#9ECBFF"> r</span></span></code></pre>]]></content:encoded></item><item><title><![CDATA[Automated snapshots in Proxmox VE]]></title><description><![CDATA[How to write Python script that will make snapshots of all virtual machines and containers in a cluster at defined intervals]]></description><link>https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/</guid><category><![CDATA[pve]]></category><category><![CDATA[python]]></category><pubDate>Tue, 31 Mar 2020 22:31:00 GMT</pubDate><content:encoded><![CDATA[<p>Backups are resource demanding because they put additional load on CPU and storage - differential backups in Proxmox Backup Server help by cutting time required to have machines dumped to backup server significantly but not to the point where we could schedule backups e.g. every hour. It’s not a lost cause though because there is another mechanism - snapshots. Snapshots are an easy and resource-wise way to protect data stored in containers and virtual machines because they just mark points in time</p>
<p><a href="https://pve.proxmox.com/pve-docs/api-viewer">Proxmox Virtual Environment  API</a> is a core element that rest of management interfaces is built on. It provides us with an easy way to automate tasks like making and deleting snapshots at programmed intervals. Lets have a look at endpoints that we will need for managing snapshots of LXC container:</p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/lxc-snapshot-get.png" alt=""></p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/lxc-snapshot-post.png" alt=""></p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/lxc-snapshot-delete.png" alt=""></p>
<p>In a similar way we can list, create and delete KVM snapshots:</p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/qemu-snapshot-get.png" alt=""></p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/qemu-snapshot-post.png" alt=""></p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/qemu-snapshot-delete.png" alt=""></p>
<p>To test how it works we can use <a href="https://pve.proxmox.com/pve-docs/pvesh.1.html">pvesh</a> - shell interface for PVE API</p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/pvesh.png" alt=""></p>
<p>Nice! With all this knowledge all what’s left is scripting requests to API. Since I’m trying to use Python for most backend stuff, after quick search I’ve found <a href="https://github.com/proxmoxer/proxmoxer">Proxmoxer</a> that will take care of authentication and making requests. What’s left is adding some basic logic and after a while I came up with this short script making snapshots of all VMs and CTs in my cluster:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> proxmoxer, datetime, time</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">pve </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> proxmoxer.ProxmoxAPI(</span><span style="color:#9ECBFF">'10.7.17.11'</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">user</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">'snapshoter@pve'</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">password</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">'passw0rd'</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">verify_ssl</span><span style="color:#F97583">=</span><span style="color:#79B8FF">False</span><span style="color:#E1E4E8">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">for</span><span style="color:#E1E4E8"> vm </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> pve.cluster.resources.get(</span><span style="color:#FFAB70">type</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">'vm'</span><span style="color:#E1E4E8">):</span></span>
<span class="line"><span style="color:#F97583">    if</span><span style="color:#E1E4E8"> vm[</span><span style="color:#9ECBFF">'type'</span><span style="color:#E1E4E8">] </span><span style="color:#F97583">==</span><span style="color:#9ECBFF"> 'lxc'</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">        cur_vm </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> pve.nodes(vm[</span><span style="color:#9ECBFF">'node'</span><span style="color:#E1E4E8">]).lxc(vm[</span><span style="color:#9ECBFF">'vmid'</span><span style="color:#E1E4E8">])</span></span>
<span class="line"><span style="color:#F97583">    else</span><span style="color:#E1E4E8"> vm[</span><span style="color:#9ECBFF">'type'</span><span style="color:#E1E4E8">] </span><span style="color:#F97583">==</span><span style="color:#9ECBFF"> 'qemu'</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">        cur_vm </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> pve.nodes(vm[</span><span style="color:#9ECBFF">'node'</span><span style="color:#E1E4E8">]).qemu(vm[</span><span style="color:#9ECBFF">'vmid'</span><span style="color:#E1E4E8">])</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">    cur_vm.snapshot.post(</span><span style="color:#FFAB70">snapname</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">'auto_'</span><span style="color:#F97583">+</span><span style="color:#E1E4E8">datetime.datetime.now().strftime(</span><span style="color:#9ECBFF">"%Y%m</span><span style="color:#79B8FF">%d</span><span style="color:#9ECBFF">%H"</span><span style="color:#E1E4E8">))</span></span></code></pre>
<p>Now just to add task to cron that will execute this script every four hours and wait. This is what I saw after two days:</p>
<p><img src="https://piotrkalinowski.com/note/automated-snapshots-in-proxmoxve/snapshot-list.png" alt=""></p>
<p>Now I just need a way to prune snapshots older than two days. To keep things simple I have created another script that is executed once a day during the night:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> proxmoxer, datetime, time</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">pve </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> proxmoxer.ProxmoxAPI(</span><span style="color:#9ECBFF">'10.7.17.11'</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">user</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">'snapshoter@pve'</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">password</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">'passw0rd'</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">verify_ssl</span><span style="color:#F97583">=</span><span style="color:#79B8FF">False</span><span style="color:#E1E4E8">)</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">for</span><span style="color:#E1E4E8"> vm </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> pve.cluster.resources.get(</span><span style="color:#FFAB70">type</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">'vm'</span><span style="color:#E1E4E8">):</span></span>
<span class="line"><span style="color:#F97583">    if</span><span style="color:#E1E4E8"> vm[</span><span style="color:#9ECBFF">'type'</span><span style="color:#E1E4E8">] </span><span style="color:#F97583">==</span><span style="color:#9ECBFF"> 'lxc'</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">        cur_vm </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> pve.nodes(vm[</span><span style="color:#9ECBFF">'node'</span><span style="color:#E1E4E8">]).lxc(vm[</span><span style="color:#9ECBFF">'vmid'</span><span style="color:#E1E4E8">])</span></span>
<span class="line"><span style="color:#F97583">    else</span><span style="color:#E1E4E8"> vm[</span><span style="color:#9ECBFF">'type'</span><span style="color:#E1E4E8">] </span><span style="color:#F97583">==</span><span style="color:#9ECBFF"> 'qemu'</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">        cur_vm </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> pve.nodes(vm[</span><span style="color:#9ECBFF">'node'</span><span style="color:#E1E4E8">]).qemu(vm[</span><span style="color:#9ECBFF">'vmid'</span><span style="color:#E1E4E8">])</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F97583">    for</span><span style="color:#E1E4E8"> snap </span><span style="color:#F97583">in</span><span style="color:#E1E4E8"> cur_vm.snapshot.get():</span></span>
<span class="line"><span style="color:#F97583">        if</span><span style="color:#E1E4E8"> snap[</span><span style="color:#9ECBFF">'name'</span><span style="color:#E1E4E8">] </span><span style="color:#F97583">!=</span><span style="color:#9ECBFF"> 'current'</span><span style="color:#F97583"> and</span><span style="color:#E1E4E8"> snap[</span><span style="color:#9ECBFF">'name'</span><span style="color:#E1E4E8">][:</span><span style="color:#79B8FF">5</span><span style="color:#E1E4E8">] </span><span style="color:#F97583">==</span><span style="color:#9ECBFF"> 'auto_'</span><span style="color:#F97583"> and</span><span style="color:#E1E4E8"> snap[</span><span style="color:#9ECBFF">'name'</span><span style="color:#E1E4E8">] </span><span style="color:#F97583">&#x3C;</span><span style="color:#9ECBFF"> 'auto_'</span><span style="color:#F97583">+</span><span style="color:#E1E4E8">(datetime.datetime.now()</span><span style="color:#F97583">-</span><span style="color:#E1E4E8">datetime.timedelta(</span><span style="color:#FFAB70">days</span><span style="color:#F97583">=</span><span style="color:#79B8FF">2</span><span style="color:#E1E4E8">)).strftime(</span><span style="color:#9ECBFF">"%Y%m</span><span style="color:#79B8FF">%d</span><span style="color:#9ECBFF">%H"</span><span style="color:#E1E4E8">):</span></span>
<span class="line"><span style="color:#E1E4E8">            cur_vm.snapshot(snap[</span><span style="color:#9ECBFF">'name'</span><span style="color:#E1E4E8">]).delete()</span></span>
<span class="line"><span style="color:#E1E4E8">            time.sleep(</span><span style="color:#79B8FF">10</span><span style="color:#E1E4E8">)</span></span></code></pre>]]></content:encoded></item><item><title><![CDATA[Single node PVE with Ceph]]></title><description><![CDATA[Short guide how to change failure domain to allow use of Ceph with only one host]]></description><link>https://piotrkalinowski.com/note/single-node-proxmox-with-ceph/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/single-node-proxmox-with-ceph/</guid><category><![CDATA[ceph]]></category><category><![CDATA[pve]]></category><pubDate>Sat, 21 Dec 2019 23:15:00 GMT</pubDate><content:encoded><![CDATA[<p>Usually when I’m testing or learning things in my lab, I do it on just one of machines that is currently unused, so in case of PVE with Ceph it would be probably NUC with two drives - one for ZFS and second for Ceph. In such config it’s easy to get it up and running because it requires only setting up replica count for pool to 1.</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ceph</span><span style="color:#9ECBFF"> osd</span><span style="color:#9ECBFF"> pool</span><span style="color:#9ECBFF"> set</span><span style="color:#9ECBFF">  size</span><span style="color:#79B8FF"> 1</span></span>
<span class="line"><span style="color:#B392F0">ceph</span><span style="color:#9ECBFF"> osd</span><span style="color:#9ECBFF"> pool</span><span style="color:#9ECBFF"> set</span><span style="color:#9ECBFF">  min_size</span><span style="color:#79B8FF"> 1</span></span></code></pre>
<p>However, recently I got Advance STOR-1 with single 500GB NVMe and four 4TB HDDs from OVH, mainly because I’ve decided to stop using multiple ARM-2T for OSDs in my Ceph cluster. One of the reasons was that  with bigger traffic it was too unstable and nonexistent support outweighed benefits coming from the low cost.</p>
<p>After installing Proxmox 6.1 via IPMI on main NVMe drive and adding four SATA drives as OSDs next step was changing failure domain to osd from default host. Because I wanted to use erasure coded pool to gain as much storage as I can simplest way was to start from creating pool with interesting me profile (in my case it was default K3M1) which caused inserting relevant rule to crush map. Of course such pool won’t be usable and Ceph will be reporting it as unhealthy because at the moment we need at least four OSDds on separate hosts to be able to use it. Having all rules that we’ll need we can move to adjusting crush map. First we have to dump and decompress it:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">ceph</span><span style="color:#9ECBFF"> osd</span><span style="color:#9ECBFF"> getcrushmap</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> crush_map_compressed</span></span>
<span class="line"><span style="color:#B392F0">crushtool</span><span style="color:#79B8FF"> -d</span><span style="color:#9ECBFF"> crush_map_compressed</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> crush_map_decompressed</span></span></code></pre>
<p>Next we will have to modify lines in our rules for replicated_rule and erasure-code starting with  “step chooseleaf”</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sed</span><span style="color:#79B8FF"> -r</span><span style="color:#9ECBFF"> 's/step chooseleaf (firstn|indep) 0 type host/step chooseleaf \1 0 type osd/g'</span><span style="color:#9ECBFF"> crush_map_decompressed</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> new_crush_map_decompressed</span></span></code></pre>
<p>After this change we can compress and import our new crush map</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">crushtool</span><span style="color:#79B8FF"> -c</span><span style="color:#9ECBFF"> new_crush_map_decompressed</span><span style="color:#79B8FF"> -o</span><span style="color:#9ECBFF"> new_crush_map_compressed</span></span>
<span class="line"><span style="color:#B392F0">ceph</span><span style="color:#9ECBFF"> osd</span><span style="color:#9ECBFF"> setcrushmap</span><span style="color:#79B8FF"> -i</span><span style="color:#9ECBFF"> new_crush_map_compressed</span></span></code></pre>
<p>This way we’ve forced Ceph to work as a simple local software RAID and now cluster shouldn’t report errors.</p>]]></content:encoded></item><item><title><![CDATA[Rasperry Pi with Canon EF lens]]></title><description><![CDATA[A while ago I've been repairing my NUC 5i5MYHE motherboard and had to replace bunch of SMD elements. It was pretty challenging task to remove 0603 components with only "Third Hand" Tool so I've started to think how to make things easier without investing]]></description><link>https://piotrkalinowski.com/note/rasperry-pi-with-canon-ef-lens/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/rasperry-pi-with-canon-ef-lens/</guid><category><![CDATA[projects]]></category><pubDate>Mon, 02 Dec 2019 20:26:00 GMT</pubDate><content:encoded><![CDATA[<p>A while ago I’ve been repairing my NUC 5i5MYHE motherboard and had to replace bunch of SMD elements. It was pretty challenging task to remove 0603 components with only “Third Hand” Tool so I’ve started to think how to make things easier without investing a ton of money on something like microscope. I had bunch of Raspberry Pi in various versions lying around, two or three camera modules and 28-30 lens with malfunctioning autofocus motor from my old EOS 33 camera - should be perfect for such project so I’ve started tinkering in Fusion 360. After multiple test prints I came up with first version that was doing what it was supposed to:</p>
<p><img src="https://piotrkalinowski.com/note/rasperry-pi-with-canon-ef-lens/Canon_EF_Lens_adapter_for_Raspberry_Pi-v1.jpg" alt=""></p>
<p><em>Right image: camera zooming on caliper (next to big three below 10” screen)</em></p>
<p>Results were pretty satisfying so I have ordered 1/4-20 UNC threaded inserts that I wanted like to add to design before releasing it to wider public and since it will be delivered in about month or so, I’ve put it back on shelf till then.</p>]]></content:encoded></item><item><title><![CDATA[AutoSSH tunnels]]></title><description><![CDATA[From time to time I have to expose ports of machine that doesn't have publicly accessible address/interface. Since I don't have public static IP in my homelab it helps me to forward http/s ports via cheap VPS that I delegate domains to. It is]]></description><link>https://piotrkalinowski.com/note/autossh-tunnels/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/autossh-tunnels/</guid><category><![CDATA[ssh]]></category><pubDate>Thu, 17 Oct 2019 00:58:00 GMT</pubDate><content:encoded><![CDATA[<p>From time to time I have to expose ports of machine that doesn’t have publicly accessible address/interface. Since I don’t have public static IP in my homelab it helps me to forward http/s ports via cheap VPS that I delegate domains to.</p>
<p>It is wise to run service under dedicated and unprivileged user so lets create one</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">useradd</span><span style="color:#9ECBFF"> autossh</span><span style="color:#79B8FF"> -g</span><span style="color:#9ECBFF"> nogroup</span><span style="color:#79B8FF"> -s</span><span style="color:#9ECBFF"> /bin/</span><span style="color:#79B8FF">false</span><span style="color:#79B8FF"> -m</span><span style="color:#9ECBFF"> /etc/autossh</span><span style="color:#9ECBFF"> autossh</span></span></code></pre>
<p>We will use SSH key to connect to remote machine</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#79B8FF"> -u</span><span style="color:#9ECBFF"> autossh</span><span style="color:#9ECBFF"> ssh-keygen</span><span style="color:#79B8FF"> -t</span><span style="color:#9ECBFF"> ed25519</span><span style="color:#79B8FF"> -C</span><span style="color:#9ECBFF"> autossh</span></span></code></pre>
<p>Next let’s define host that we will be forwarding ports to (or from)</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">Host</span><span style="color:#9ECBFF">    homelab-vps</span></span>
<span class="line"><span style="color:#B392F0">        HostName</span><span style="color:#79B8FF">        10.10.10.10</span></span>
<span class="line"><span style="color:#B392F0">        User</span><span style="color:#9ECBFF">            root</span></span></code></pre>
<p><em>/etc/autossh/.ssh/config</em></p>
<p>Now lets test connection. Additionally our machine will be added to known_hosts</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">sudo</span><span style="color:#79B8FF"> -u</span><span style="color:#9ECBFF"> autossh</span><span style="color:#9ECBFF"> ssh</span><span style="color:#9ECBFF"> homelab-vps</span></span></code></pre>
<p>Before closing connection we have to modify /etc/ssh/sshd_config on machine we will be forwarding ports to by adding “GatewayPorts yes”.</p>
<p>Systemd unit will allow us to start tunnel automatically with operating system</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> /etc/systemd/system/autossh@.service</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">[Unit]</span></span>
<span class="line"><span style="color:#9ECBFF">Description=Keeps an ssh tunnel to %I open</span></span>
<span class="line"><span style="color:#9ECBFF">After=network-online.target ssh.service</span></span>
<span class="line"></span>
<span class="line"><span style="color:#9ECBFF">[Service]</span></span>
<span class="line"><span style="color:#9ECBFF">User=autossh</span></span>
<span class="line"><span style="color:#9ECBFF"># no monitoring</span></span>
<span class="line"><span style="color:#9ECBFF">Environment="AUTOSSH_PORT=0"</span></span>
<span class="line"><span style="color:#9ECBFF"># Disable gatetime behaviour</span></span>
<span class="line"><span style="color:#9ECBFF">Environment="AUTOSSH_GATETIME=0"</span></span>
<span class="line"><span style="color:#9ECBFF"># Enable logging</span></span>
<span class="line"><span style="color:#9ECBFF">Environment="AUTOSSH_DEBUG=1"</span></span>
<span class="line"><span style="color:#9ECBFF">Environment="AUTOSSH_LOGFILE=/var/log/autossh/%i.log"</span></span>
<span class="line"><span style="color:#9ECBFF">EnvironmentFile=/etc/autossh/%i.conf</span></span>
<span class="line"><span style="color:#9ECBFF">RestartSec=3</span></span>
<span class="line"><span style="color:#9ECBFF">Restart=always</span></span>
<span class="line"></span>
<span class="line"><span style="color:#9ECBFF"># -NT Just open the connection and do nothing (not interactive, no tty alloc)</span></span>
<span class="line"><span style="color:#9ECBFF"># use /usr/bin/ssh instead of autossh is good as well</span></span>
<span class="line"><span style="color:#9ECBFF">ExecStart=/usr/bin/autossh -NT -o "ExitOnForwardFailure=yes" </span><span style="color:#E1E4E8">$SSH_OPTIONS</span><span style="color:#9ECBFF"> ${</span><span style="color:#E1E4E8">TARGET_HOST</span><span style="color:#9ECBFF">} </span><span style="color:#E1E4E8">$FORWARDS</span></span>
<span class="line"><span style="color:#9ECBFF">TimeoutStopSec=10</span></span>
<span class="line"></span>
<span class="line"><span style="color:#9ECBFF">[Install]</span></span>
<span class="line"><span style="color:#9ECBFF">WantedBy=multi-user.target</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<p>For each connection we should create config file</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> ></span><span style="color:#9ECBFF"> /etc/autossh/homelab-vps.conf</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">TARGET_HOST=homelab-vps</span></span>
<span class="line"><span style="color:#9ECBFF">FORWARDS=-R 80:localhost:80 -R 443:localhost:443</span></span>
<span class="line"><span style="color:#9ECBFF">SSH_OPTIONS=-o "ServerAliveInterval=10" -o "ServerAliveCountMax=3"</span></span>
<span class="line"><span style="color:#9ECBFF">AUTOSSH_PORT=0</span></span>
<span class="line"><span style="color:#9ECBFF">AUTOSSH_GATETIME=0</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<p>Finally, to activate tunnel:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> enable</span><span style="color:#9ECBFF"> autossh@homelab-vps</span></span>
<span class="line"><span style="color:#B392F0">systemctl</span><span style="color:#9ECBFF"> start</span><span style="color:#9ECBFF"> autossh@homelab-vps</span></span></code></pre>
<p>We can of course forward ports in different direction - from remote to local machine.</p>
<p>This time we have to modify ssh server config on machine that will be used to forward ports. One thing to note: privileged ports (1-1023) can only be forwarded by root, in this scenario we will use dynamic port</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> >></span><span style="color:#9ECBFF"> /etc/ssh/sshd_config</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">Match User autossh</span></span>
<span class="line"><span style="color:#9ECBFF">    PasswordAuthentication no</span></span>
<span class="line"><span style="color:#9ECBFF">    GatewayPorts yes</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> >></span><span style="color:#9ECBFF"> /etc/autossh/.ssh/config</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">Host    mariadb</span></span>
<span class="line"><span style="color:#9ECBFF">        HostName        10.1.1.50</span></span>
<span class="line"><span style="color:#9ECBFF">        User            root</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>
<p>Config in such scenario may look like this (in case of mysql or mariadb there’s a reason not to use localhost - all connection will be seen as coming from it by dbms)</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="bash"><code><span class="line"><span style="color:#B392F0">cat</span><span style="color:#F97583"> >></span><span style="color:#9ECBFF"> /etc/autossh/mariadb.config</span><span style="color:#F97583"> &#x3C;&#x3C;</span><span style="color:#9ECBFF"> EOF</span></span>
<span class="line"><span style="color:#9ECBFF">TARGET_HOST=mariadb</span></span>
<span class="line"><span style="color:#9ECBFF">FORWARDS=-L 0.0.0.0:3306:10.1.1.50:3306</span></span>
<span class="line"><span style="color:#9ECBFF">SSH_OPTIONS=-o "ServerAliveInterval=10" -o "ServerAliveCountMax=3"</span></span>
<span class="line"><span style="color:#9ECBFF">AUTOSSH_PORT=0</span></span>
<span class="line"><span style="color:#9ECBFF">AUTOSSH_GATETIME=0</span></span>
<span class="line"><span style="color:#9ECBFF">EOF</span></span></code></pre>]]></content:encoded></item><item><title><![CDATA[Managing Windows and Linux with Python]]></title><description><![CDATA[Once in a while I need a way to execute something on remote machine as part of scripting I'm currently working on. Linux With Linux distros (it works fine with other systems that are hosting ssh server, including Windows) I usually use paramiko - it's quite]]></description><link>https://piotrkalinowski.com/note/managing-windows-and-linux-bsd-with-python/</link><guid isPermaLink="true">https://piotrkalinowski.com/note/managing-windows-and-linux-bsd-with-python/</guid><category><![CDATA[python]]></category><pubDate>Tue, 17 Sep 2019 00:07:00 GMT</pubDate><content:encoded><![CDATA[<p>Once in a while I need a way to execute something on remote machine as part of scripting I’m currently working on.</p>
<h3 id="linux">Linux</h3>
<p>With Linux distros (it works fine with other systems that are hosting ssh server, including Windows) I usually use <a href="http://www.paramiko.org/">paramiko</a> - it’s quite easy to use and supports all what one might need (including key-based auth, which inter alia gives more granular control which makes it far more reasonable solution than using passwords). Here’s simple script to check how much of space we’re using on /tmp</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> paramiko, re</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">hostname </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> '192.168.1.110'</span></span>
<span class="line"><span style="color:#E1E4E8">username </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> 'piotr'</span></span>
<span class="line"><span style="color:#E1E4E8">password </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> 'piotr'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">ssh </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> paramiko.SSHClient()</span></span>
<span class="line"><span style="color:#E1E4E8">ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())</span></span>
<span class="line"><span style="color:#E1E4E8">ssh.connect(</span><span style="color:#FFAB70">hostname</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">hostname, </span><span style="color:#FFAB70">username</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">username, </span><span style="color:#FFAB70">password</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">password)</span></span>
<span class="line"><span style="color:#E1E4E8">stdin, stdout, stderr </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> ssh.exec_command(</span><span style="color:#9ECBFF">'df /tmp'</span><span style="color:#E1E4E8">)</span></span>
<span class="line"><span style="color:#79B8FF">print</span><span style="color:#E1E4E8">(re.findall(</span><span style="color:#F97583">r</span><span style="color:#9ECBFF">'</span><span style="color:#79B8FF">\s(\d</span><span style="color:#F97583">+</span><span style="color:#79B8FF">)</span><span style="color:#DBEDFF">%</span><span style="color:#9ECBFF">'</span><span style="color:#E1E4E8">, stdout.read().decode(</span><span style="color:#9ECBFF">'ascii'</span><span style="color:#E1E4E8">))[</span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">])</span></span>
<span class="line"><span style="color:#E1E4E8">ssh.close()</span></span></code></pre>
<h2 id="windows">Windows</h2>
<p>For Windows-based machines I prefer <a href="https://www.bloggingforlogging.com/2018/03/12/introducing-psexec-for-python/">pypsexec</a> - it doesn’t require too much setup on remote machine. There’s great manual at <a href="https://pypi.org/project/pypsexec/">Python Package Index</a> so I don’t think there’s a point in replicating it’s contents here. Lets check how much of storage is used on drive C:</p>
<pre class="astro-code github-dark" style="background-color:#24292e;color:#e1e4e8; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;" tabindex="0" data-language="python"><code><span class="line"><span style="color:#F97583">import</span><span style="color:#E1E4E8"> pypsexec.client</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">hostname </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> '192.168.1.80'</span></span>
<span class="line"><span style="color:#E1E4E8">username </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> 'Piotr'</span></span>
<span class="line"><span style="color:#E1E4E8">password </span><span style="color:#F97583">=</span><span style="color:#9ECBFF"> 'Piotr'</span></span>
<span class="line"></span>
<span class="line"><span style="color:#E1E4E8">c </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> pypsexec.client.Client(hostname, </span><span style="color:#FFAB70">username</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">username, </span><span style="color:#FFAB70">password</span><span style="color:#F97583">=</span><span style="color:#E1E4E8">password, </span><span style="color:#FFAB70">encrypt</span><span style="color:#F97583">=</span><span style="color:#79B8FF">False</span><span style="color:#E1E4E8">)</span></span>
<span class="line"><span style="color:#E1E4E8">c.connect()</span></span>
<span class="line"><span style="color:#F97583">try</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">	c.create_service()</span></span>
<span class="line"><span style="color:#E1E4E8">	stdout </span><span style="color:#F97583">=</span><span style="color:#E1E4E8"> c.run_executable(</span><span style="color:#9ECBFF">"powershell.exe"</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">arguments</span><span style="color:#F97583">=</span><span style="color:#9ECBFF">"-"</span><span style="color:#E1E4E8">, </span><span style="color:#FFAB70">stdin</span><span style="color:#F97583">=</span></span>
<span class="line"><span style="color:#9ECBFF">"""$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'"</span></span>
<span class="line"><span style="color:#9ECBFF">[math]::round(($disk.Size-$disk.FreeSpace)/$disk.Size*100)</span></span>
<span class="line"><span style="color:#9ECBFF">exit 0</span></span>
<span class="line"><span style="color:#9ECBFF">"""</span><span style="color:#E1E4E8">.encode(</span><span style="color:#9ECBFF">'utf-8'</span><span style="color:#E1E4E8">), </span><span style="color:#FFAB70">timeout_seconds</span><span style="color:#F97583">=</span><span style="color:#79B8FF">30</span><span style="color:#E1E4E8">)</span></span>
<span class="line"><span style="color:#79B8FF">	print</span><span style="color:#E1E4E8">(stdout[</span><span style="color:#79B8FF">0</span><span style="color:#E1E4E8">].decode(</span><span style="color:#9ECBFF">'utf-8'</span><span style="color:#E1E4E8">).strip())</span></span>
<span class="line"><span style="color:#F97583">finally</span><span style="color:#E1E4E8">:</span></span>
<span class="line"><span style="color:#E1E4E8">	c.remove_service()</span></span>
<span class="line"><span style="color:#E1E4E8">	c.disconnect()</span></span></code></pre>]]></content:encoded></item></channel></rss>