<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>/var/log/tzermias</title>
		<description>Various thoughts and ideas from a (so-called) computer scientist
</description>
		<link>https://blog.tzermias.com</link>
		<atom:link href="https://blog.tzermias.com/feed.xml" rel="self" type="application/rss+xml" />
		
			<item>
				<title>Deploying a software RIPE atlas probe and ppp</title>
				<description>&lt;p&gt;On 2010 RIPE Network Coordination Centre (RIPE NCC) established a distributed platform for Internet measurements called “&lt;a href=&quot;https://atlas.ripe.net&quot;&gt;RIPE Atlas&lt;/a&gt;”.&lt;br /&gt;
The project consists of multiple hardware devices, called probes, that conduct measurements such as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ping&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;traceroute&lt;/code&gt; to specific destinations.&lt;br /&gt;
The concept is to hand over RIPE Atlas probes free of change to volunteers, which in turn install them to their networks and contribute a small portion of their bandwidth to the project.&lt;br /&gt;
As an incentive, RIPE provides “credits” to volunteers based on their probe uptime. So the more the uptime your probe has, the more the credits you get.&lt;br /&gt;
Credits can be redeemed, by creating and conducting custom measurements on the platform.&lt;br /&gt;
Currently, more than 11.000 probes have been deployed globally and many network tools have been developed, based on this platform.&lt;br /&gt;
One of those probes is hosted on my parent’s house in Heraklion, Crete since 2013.&lt;/p&gt;

&lt;p&gt;In February 2020, RIPE announced the availability of &lt;a href=&quot;https://labs.ripe.net/Members/alun_davies/ripe-atlas-software-probes&quot;&gt;software probes&lt;/a&gt;, to improve platform coverage even on smaller networks. So instead of installing a network device (the probe) to your network, you install the software package for the probe in a machine connected to your network.&lt;br /&gt;
RIPE provides packages to install the probe at CentOS and Debian distributions. There is even a &lt;a href=&quot;https://github.com/Jamesits/docker-ripe-atlas&quot;&gt;Docker image&lt;/a&gt; developed by the community.&lt;br /&gt;
I used the latter option, to host another probe on my home’s OrangePI.&lt;/p&gt;

&lt;p&gt;One might reasonably wonder though. “Hey, do you trust that this device won’t intercept your local network traffic, or tamper with your other devices in any way?”. &lt;br /&gt;
As stated on the &lt;a href=&quot;https://atlas.ripe.net/about/faq/#security-and-privacy&quot;&gt;FAQ&lt;/a&gt;, the probe executes measurement commands against the public internet only. &lt;br /&gt;
For the security cautious, it is advised that the probe should be install outside of one’s local network (e.g on a DMZ network). I had followed this recommendation on my hardware probe before, but how am I going to perform such isolation in Docker?&lt;br /&gt;
To make matters worse, I am using the CPE provided by my ISP, which has very limited capabilities in terms of configuring new networks.&lt;br /&gt;
One possible solution is to reject any traffic from probe’s network to internal networks via iptables.&lt;br /&gt;
However, this would require additional steps when redeploying the atlas probe. Ideally, my goal is to deploy the software probe out-of-the-box using a Docker compose manifest, without any additional commands.&lt;/p&gt;

&lt;p&gt;So what if network traffic of our software probe container can be proxied to another service, which in turn tunnels it to the public Internet?&lt;br /&gt;
In this post we are going to describe how to achieve this, by spinning up a dedicated PPP connection with our ISP in Docker and use it as a “gateway” to our software probe container.&lt;/p&gt;

&lt;h2 id=&quot;design&quot;&gt;Design&lt;/h2&gt;
&lt;p&gt;The overall design can be depicted on the following figure&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/ripe-atlas-design.png&quot; alt=&quot;Overall design&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Our goal is to initiate a new PPPoE connection from a container inside an isolated network. Thus our ripe-atlas probe can only perform its measurements only via ppp connection, and without interfering with adjacent containers on the same host.&lt;/p&gt;

&lt;h2 id=&quot;ppp-client&quot;&gt;PPP client&lt;/h2&gt;
&lt;p&gt;There are two prerequisites so that ppp is established correctly. First of all you need to ensure that the CPE (modem/router) of your ISP has “PPPoE Passthrough” enabled. Some ISPs have this setting enabled by default.&lt;br /&gt;
Next, is to retrieve your ISP username and password. Some ISPs (like mine) had handed over the username and password on paper along with my CPE equipment. On other circumstances, you might want to fetch a configuration backup from your CPE and retrieve credentials from it. YMMV. With those in hand we can proceed with configuring ppp client.&lt;/p&gt;

&lt;p&gt;Required ppp configuration can be easily generated using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pppoeconf&lt;/code&gt; tool. It is an ncurses based tool that helps you populate &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ppp/peers/dsl-provider&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ppp/chap-secrets&lt;/code&gt; with the correct values.&lt;br /&gt;
Next step, is to dockerise the ppp client. I created a small Docker image (&lt;a href=&quot;https://hub.docker.com/r/tzermias/ppp/&quot;&gt;tzermias/ppp&lt;/a&gt;) that it simply invokes ppp client.&lt;br /&gt;
Providing that our configuration is under a file named “dsl-provider” and located under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ppp/peers&lt;/code&gt; directory, we could invoke the container as follows:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run --name ppp -d --privileged \
     --device=/dev/ppp \
     - v/etc/ppp:/etc/ppp \
     tzermias/ppp call dsl-provider
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ppp client requires access to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/ppp&lt;/code&gt; device to work properly, so we need to expose it accordingly.&lt;br /&gt;
Furthermore, you need to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;macvlan&lt;/code&gt; network driver for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppp&lt;/code&gt; container to work properly.&lt;br /&gt;
A dedicated &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;macvlan&lt;/code&gt; network can be created using the command below.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker network create -d macvlan \
     --subnet=172.16.86.0/24 \
     --gateway=172.16.86.1
     -o parent=eth0 ppp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The ppp container can be attached to the network by adding the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--network ppp&lt;/code&gt; flag on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run&lt;/code&gt; command above.&lt;/p&gt;

&lt;p&gt;If everything went well, logs of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppp&lt;/code&gt; container would indicate a successful call is performed and a new IPv4 address is assigned to ppp0 interface of our container.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker logs ppp
Plugin rp-pppoe.so loaded.
PPP session is 394
Connected to d8:67:d9:48:XX:XX via interface eth0
Using interface ppp0
Connect: ppp0 &amp;lt;--&amp;gt; eth0
PAP authentication succeeded
peer from calling number D8:67:D9:48:XX:XX authorized
local  LL address fe80::dead:beef:dead:beed
remote LL address fe80::beef:beef:dead:dead
replacing old default route to eth0 [172.16.86.1]
local  IP address XX.XX.XX.XX
remote IP address YY.YY.YY.YY
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;ppp client will also create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolv.conf&lt;/code&gt; file under /etc/ppp, containing DNS nameservers obtained from our peer.&lt;br /&gt;
For this, you need to have the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;usepeerdns&lt;/code&gt; option in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ppp/peers/dsl-provider&lt;/code&gt; file.&lt;/p&gt;

&lt;h2 id=&quot;container-networking&quot;&gt;Container networking&lt;/h2&gt;
&lt;p&gt;Now comes the interesting part. How can we ensure that any network traffic from our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ripe-atlas&lt;/code&gt; container will only pass through the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ppp&lt;/code&gt; container we started earlier?&lt;br /&gt;
The answer is to share the network stack of this container. Apart from the usual &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bridge&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;host&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;none&lt;/code&gt; options that one can pass to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--network&lt;/code&gt; setting, there a special option named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;container&lt;/code&gt; which allows you to use the network stack of another container.&lt;br /&gt;
According to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;docker run&lt;/code&gt; &lt;a href=&quot;https://docs.docker.com/engine/reference/run/#network-settings&quot;&gt;reference&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;With the network set to container a container will share the network stack of another container. The other container’s name must be provided in the format of –network container:&amp;lt;name|id&amp;gt;.&lt;br /&gt;
…&lt;br /&gt;
Example running a Redis container with Redis binding to localhost then running the redis-cli command and connecting to the Redis server over the localhost interface.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;With ppp container running, we can easily validate that our setup works, just by spinning up a test container as follows, and perform some tests (e.g a traceroute).&lt;br /&gt;
Don’t forget to mount &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ppp/resolv.conf&lt;/code&gt; file in this container in order to have proper DNS resolution.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ docker run -it --network ppp -v /etc/ppp/resolv.conf:/etc/resolv.conf:ro busybox:latest traceroute google.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now we are ready to spin up our ripe-atlas probe!&lt;/p&gt;

&lt;h2 id=&quot;ripe-atlas-in-docker&quot;&gt;RIPE Atlas in Docker&lt;/h2&gt;
&lt;p&gt;I used &lt;a href=&quot;https://hub.docker.com/r/jamesits/ripe-atlas&quot;&gt;ripe-atlas&lt;/a&gt; image by jamesits for this purpose. Probe installation and registration are straightforward and well-documented.&lt;br /&gt;
On first run, probe generates an SSH keypair and saves it under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/var/atlas-probe/etc/probe-key.pub&lt;/code&gt;.&lt;br /&gt;
Simply create a new directory where any relevant &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ripe-atlas&lt;/code&gt; files will be stored and mount it to the container.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ mkdir -p atlas-probe

$ docker run --network &quot;container:ppp&quot; \
        --detach --restart=always --log-opt max-size=10m \
	--cpus=1 --memory=64m --memory-reservation=64m \
	--cap-add=SYS_ADMIN --cap-add=NET_RAW --cap-add=CHOWN \
	--mount type=tmpfs,destination=/var/atlasdata,tmpfs-size=64M \
	-v ${PWD}/atlas-probe/etc:/var/atlas-probe/etc \
	-v ${PWD}/atlas-probe/status:/var/atlas-probe/status \
        -v /etc/ppp/resolv.conf:/etc/resolv.conf:ro \
	-e RXTXRPT=yes --name ripe-atlas \
	jamesits/ripe-atlas:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After uploading the probe’s public key to RIPE Atlas WebUI, probe is ready to accept new measurements.&lt;/p&gt;

&lt;h2 id=&quot;ipv6-support&quot;&gt;IPv6 support&lt;/h2&gt;
&lt;p&gt;For those who wish the probe run IPv6 measurements, you can enable IPv6 support by performing the following modifications:&lt;/p&gt;

&lt;p&gt;Firstly you need to enable IPv6 support in Docker daemon. Ensure that your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/docker/daemon.json&lt;/code&gt; contains the following:&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;ipv6&quot;: true,
  &quot;fixed-cidr-v6&quot;: &quot;2001:db8:1::/64&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then, ensure that Docker daemon is aware of those settings&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next step is to make sure that our ppp container has IPv6 support enabled. For this we need to start our container with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net.ipv6.conf.all.disable_ipv6=0&lt;/code&gt; set.&lt;/p&gt;

&lt;p&gt;And the last step (eventually) is to enable IPv6 support when performing the PPP call. This can be achieved by adding the following two options in our &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/ppp/peers/dsl-provider&lt;/code&gt; config.&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;+ipv6
ipv6cp-use-persistent

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

&lt;h2 id=&quot;putting-it-together&quot;&gt;Putting it together&lt;/h2&gt;
&lt;p&gt;To sum up, one should execute the following commands to have the probe and the ppp client up and running:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;# Create network
docker network create -d macvlan --subnet=172.16.86.0/24 --gateway=172.16.86.1 -o parent=eth0  ppp

# Create ppp container
docker run --name ppp --network ppp --restart unless-stopped\
       -d --privileged --device=/dev/ppp \
       --sysctl net.ipv6.conf.all.disable_ipv6=0  \
       -v /etc/ppp:/etc/ppp \
       tzermias/ppp call dsl-provider

# Create directory for atlas-probe config
mkdir -p atlas-probe

# Create ripe-atlas container
docker run --network &amp;quot;container:ppp&amp;quot; \
        --detach --restart=always --log-opt max-size=10m \
        --cpus=1 --memory=64m --memory-reservation=64m \
        --cap-add=SYS_ADMIN --cap-add=NET_RAW --cap-add=CHOWN \
        --mount type=tmpfs,destination=/var/atlasdata,tmpfs-size=64M \
        -v ${PWD}/atlas-probe/etc:/var/atlas-probe/etc \
        -v ${PWD}/atlas-probe/status:/var/atlas-probe/status \
        -v /etc/ppp/resolv.conf:/etc/resolv.conf:ro \
        -e RXTXRPT=yes --name ripe-atlas \
        jamesits/ripe-atlas:latest
&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/tzermias/42f4bf8942d945e4440b768986154d9a.js?file=commands.txt&quot;&gt; &lt;/script&gt;

&lt;p&gt;I also created the following docker-compose.yaml file to spin up the network and the containers to avoid typing those commands again and again.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;version: &amp;#39;2.1&amp;#39;

networks:
  ppp:
    driver: macvlan
    driver_opts:
      parent: eth0
    ipam:
      config:
        - subnet: 172.16.86.0/24
          gateway: 172.16.86.1

services:
  ppp:
    container_name: ppp
    image: tzermias/ppp:latest
    restart: always
    privileged: true
    sysctls:
      - net.ipv6.conf.all.disable_ipv6=0
    volumes:
      - /etc/ppp:/etc/ppp
    devices:
      - /dev/ppp:/dev/ppp
    networks:
      - ppp
    command:
      - &amp;quot;call&amp;quot;
      - &amp;quot;dsl-provider&amp;quot;
  ripe-atlas:
    container_name: ripe-atlas
    image: jamesits/ripe-atlas:latest
    restart: unless-stopped
    volumes:
      - ${PWD}/atlas-probe/etc:/var/atlas-probe/etc
      - ${PWD}/atlas-probe/status:/var/atlas-probe/status
      - /etc/ppp/resolv.conf:/etc/resolv.conf:ro
    tmpfs:
      - /var/atlasdata:size=64M
    environment:
      - RXTXRPT=yes
    cap_add:
      - SYS_ADMIN
      - NET_RAW
      - CHOWN
    network_mode: &amp;quot;service:ppp&amp;quot;
    depends_on:
      - ppp
&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/tzermias/42f4bf8942d945e4440b768986154d9a.js?file=docker-compose.yml&quot;&gt; &lt;/script&gt;

&lt;p&gt;For those who wish to use this probe for their measurements, just use probe &lt;a href=&quot;https://atlas.ripe.net/probes/1001487/&quot;&gt;#1001487&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Software probes can increase the reach of RIPE Atlas platforms on more networks and geographic locations.&lt;br /&gt;
From 260 probes currently deployed in Greece, we can clearly observe a large portion of them being deployed in Athens metro area.&lt;br /&gt;
Wouldn’t be nice to have Internet measurements on less densely populated areas, like islands?&lt;br /&gt;
Furthermore, the option to share one container’s network stack with another can be leveraged on other applications, like proxying traffic through a VPN tunnel.&lt;br /&gt;
If you have a RaspberryPi sitting idle on your network, I’d suggest you give this option a try!&lt;/p&gt;

</description>
				<pubDate>Thu, 08 Apr 2021 23:03:00 +0000</pubDate>
				<link>https://blog.tzermias.com/2021/04/ripe-atlas-software-probe/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/2021/04/ripe-atlas-software-probe/</guid>
			</item>
		
			<item>
				<title>Creating a timelapse</title>
				<description>&lt;p&gt;Few days ago, I noticed that you can enjoy a scenic view of the Attica basin as shown from the foothills of Mount&lt;br /&gt;
Penteli via a set of web cameras.  In particular, &lt;a href=&quot;https://meteo.gr&quot;&gt;National Observatory of Athens/meteo.gr&lt;/a&gt; has installed two cameras on the Penteli Astronomical Station premises.&lt;/p&gt;

&lt;p&gt;One camera has a view to the south of the basin with Mt. Hymettus on the left, while the other covers the&lt;br /&gt;
southwestern part (Mt. Aigaleo and Mt. Parnitha).  As with other weather cameras, only still images are provided&lt;br /&gt;
that are refreshed at a one-minute interval, rather than a live feed.&lt;br /&gt;
Resolution of each image is 2688x1520. Feed for both cameras is available &lt;a href=&quot;https://www.meteo.gr/camerasMain.cfm&quot;&gt;here&lt;/a&gt;. To make a step further, meteo.gr is courteous enough a “panorama” that is synthesized from the images of the cameras. Each “panorama” has a resolution of 4190x1394 pixels. Contrary to the actual cameras, panorama is refreshed every two minutes.&lt;/p&gt;

&lt;p&gt;So, I thought that this panorama is a prime source of creating a timelapse video of Athens. &lt;br /&gt;
Collecting the images is a rudimentary process. &lt;br /&gt;
Every two minutes a script is invoked that fetches the panorama image and saves it locally following a predetermined naming scheme:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;400: Invalid request&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/f3ce1320e64d1208fb1a467bb43cbfd6.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;Then, I set a cronjob to my humble Orange Pi, in order to invoke the script every two minutes.&lt;br /&gt;
24 hours and 700 images later, raw material for the video has been collected!&lt;/p&gt;

&lt;p&gt;So moving to the next step of creating a video out of these still images. For simplicity, I opt using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt; to render&lt;br /&gt;
the whole video.  FFmpeg can render a video using a sequence of images by specifying the following &lt;br /&gt;
flags; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-pattern_type glob -i &amp;lt;IMG_FOLDER&amp;gt;/*.jpg&lt;/code&gt;. Also, you need to specify the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-r&lt;/code&gt; flag to set to a reasonable frame rate. Here, I used 12 fps. &lt;br /&gt;
Moreover, FFmpeg provides a variety of audio/video filters that can be applied during video rendering. The complete documentation of FFmpeg filters is available &lt;a href=&quot;https://ffmpeg.org/ffmpeg-filters.html&quot;&gt;here&lt;/a&gt;.&lt;br /&gt;
Thus, I used &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;fade&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;afade&lt;/code&gt; filters to add fade-in and fade-out effects on video and audio sources respectively.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;400: Invalid request&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/48e5c0d2b94b576a2404085690cf03c1.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;Rendering took approximately 2-3 minutes. The final result is shown below:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;420&quot; src=&quot;https://www.youtube.com/embed/AYTqC2N6228?color=white&amp;amp;theme=light&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;The glitch at the middle of the image is due to an webcam image being sightly misplaced during the merging of the two sources.&lt;br /&gt;
I was astonished with the fact that you can create a complete video just by using two commands; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curl&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt;!&lt;br /&gt;
Hope this small post will help you creating your own timelapses, either from readily available sources (like&lt;br /&gt;
web cameras) or even your own captures!&lt;/p&gt;
</description>
				<pubDate>Mon, 27 Apr 2020 00:00:00 +0000</pubDate>
				<link>https://blog.tzermias.com/2020/04/athens-timelapse/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/2020/04/athens-timelapse/</guid>
			</item>
		
			<item>
				<title>Revisiting an Ansible role and integrate testing with molecule</title>
				<description>&lt;p&gt;Five years ago, I had developed an Ansible role that facilitates the&lt;br /&gt;
installation and basic configuration of &lt;a href=&quot;https://www.plesk.com/&quot;&gt;Plesk&lt;/a&gt; for Linux. Plesk is a commercial web hosting control&lt;br /&gt;
panel and it is widely adopted in various shared web hosting companies.&lt;br /&gt;
According to &lt;a href=&quot;https://docs.plesk.com/en-US/12.5/deployment-guide/installing-plesk/manual-installation/installation-from-the-command-line.65780/&quot;&gt;Plesk documentation&lt;/a&gt;, the installation process is straightforward; Download and run an installation script locally, that would guide you through the installation process. &lt;br /&gt;
By passing some  parameters to the installation script, installation is performed unattended.&lt;/p&gt;

&lt;p&gt;The goal of this Ansible role was to perform an unattended installation for pre-determined Plesk version and also perform some post-installation tasks (such as run some initial configuration steps for Plesk or install a Plesk license). &lt;br /&gt;
The role, named &lt;a href=&quot;https://galaxy.ansible.com/tzermias/plesk/&quot;&gt;ansible-plesk&lt;/a&gt; is available in Ansible Galaxy, and its source code is available in&lt;br /&gt;
&lt;a href=&quot;https://github.com/tzermias/ansible-plesk/&quot;&gt;Github&lt;/a&gt;. I made this role just for experimentation in order to learn Ansible.&lt;/p&gt;

&lt;p&gt;In order to test the role, I used to spin a virtual machine (usually CentOS 7) and run the role against this machine.&lt;br /&gt;
During its installation, Plesk performs numerous changes on the underlying host (install services such as dovecot, httpd, mysql etc.) hence the only option to ensure that the role works as expected, was using a full-blown virtual machine.&lt;br /&gt;
This method was cumbersome and also required some resources.&lt;br /&gt;
In particular, the virtual machine should be created, destroyed, recreated across tests.&lt;br /&gt;
Not to mention the possibility of using a different OS version (CentOS 6) or even a different linux distribution.&lt;br /&gt;
In other words I would seek for a solution to test Ansible roles, where the testing environment would be as close as a virtual machine but without all the maintenance hassle.&lt;/p&gt;

&lt;p&gt;Recently, I came across a &lt;a href=&quot;https://www.jeffgeerling.com/blog/2018/testing-your-ansible-roles-molecule/&quot;&gt;blog post&lt;/a&gt; by Jeff Geerling, with regards to test his Ansible roles with Molecule. &lt;br /&gt;
Jeff has developed a variety of Ansible &lt;a href=&quot;https://galaxy.ansible.com/geerlingguy/&quot;&gt;roles&lt;/a&gt; available on Ansible Galaxy as well as is the author of the &lt;a href=&quot;https://www.ansiblefordevops.com/&quot;&gt;“Ansible for DevOps”&lt;/a&gt; book. As I wanted to give molecule a try, I thought that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible-plesk&lt;/code&gt; role is a good candidate.&lt;br /&gt;
Besides, the code had been left untouched for years, so it was a perfect opportunity to perform a refactoring, if needed. Following instructions omit lots of details for brevity.&lt;/p&gt;

&lt;p&gt;I started with installing molecule on my laptop using pip&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ pip install molecule molecule[docker]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then I created the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;molecule/default&lt;/code&gt; directory in the role. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;molecule&lt;/code&gt; directory contains all tests (called “scenarios”) for that role. &lt;br /&gt;
Molecule expects that each role has a default scenario, hence the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;default&lt;/code&gt; directory. Core configuration exists under &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;molecule.yml&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;driver&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;docker&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;platforms&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;instance&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;geerlingguy/docker-centos7-ansible:latest&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/sys/fs/cgroup:/sys/fs/cgroup:ro&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;privileged&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;pre_build_image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;provisioner&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ansible&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;lint&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ansible-lint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Molecule can use Docker containers as test platforms. In a nutshell, you can use a pre-built Docker container (e.g a Centos container with systemd) where your role would run. Jeff also maintains some base Docker images tailored for the purpose. &lt;br /&gt;
Setting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;privileged: true&lt;/code&gt; is inevitable when our role is performing changes on systemd units (which in our case, it does).&lt;/p&gt;

&lt;p&gt;The next step was to create a playbook that invokes the role. Molecule expects a specific playbook called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;converge.yml&lt;/code&gt; to be present. &lt;br /&gt;
This playbook is invoked by molecule and is run against the instance defined on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;molecule.yml&lt;/code&gt;.&lt;br /&gt;
It could be as simple as the following&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Converge&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;hosts&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;roles&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ansible-plesk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We are now ready to run our Ansible role with molecule. Simply run&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;molecule test
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This would create the testing environment, invoke converge.yml to run the role, re-invoke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;converge.yml&lt;/code&gt; to test whether our role is idempotent or not and finally destroy the testing environment. &lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;test&lt;/code&gt;also performs other tasks as well (such as linting).&lt;/p&gt;

&lt;p&gt;By incorporating these changes to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ansible-plesk&lt;/code&gt;, I managed to successfully migrate my role testing to Molecule. Moreover, I can now test my changes locally with minimal effort. &lt;br /&gt;
Incorporating molecule with an existing role was also really simple,  if you wish some basic testing to your role. &lt;br /&gt;
I even found an issue when the role was running on Ansible 2.9 and pushed the relevant fix to upstream.&lt;/p&gt;

&lt;p&gt;All in all, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;molecule&lt;/code&gt; combined with pre-built Docker containers by Jeff Geerling is a compelling option when it comes to test Ansible roles. &lt;br /&gt;
I would suggest reading the &lt;a href=&quot;https://www.jeffgeerling.com/blog/2018/testing-your-ansible-roles-molecule/&quot;&gt;blog post&lt;/a&gt; for a more detailed approach on how to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;molecule&lt;/code&gt;.&lt;/p&gt;
</description>
				<pubDate>Wed, 25 Mar 2020 00:00:00 +0000</pubDate>
				<link>https://blog.tzermias.com/2020/03/ansible-plesk/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/2020/03/ansible-plesk/</guid>
			</item>
		
			<item>
				<title>Watching Nagios/Icinga status in tmux status line</title>
				<description>&lt;p&gt;For the past few months I use Tmux in a daily basis as my terminal multiplexor. It is a very handy tool that solves limitations of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen&lt;/code&gt; as well as provides some new features.&lt;br /&gt;
I even integrated a tmux session in Guake and completely disable Guake tabs!&lt;/p&gt;

&lt;p&gt;As a systems administrator, it is essential to have a monitoring/alerting system in your infrastructure. &lt;br /&gt;
When something happens on one of your systems (i.e. server exhibits an ever-increasing CPU load or Apache stops responding) you should be the first to know.&lt;br /&gt;
For this, I use &lt;a href=&quot;https://www.icinga.com/&quot;&gt;Icinga&lt;/a&gt;.  Icinga started as a Nagios fork and introduced features like high availability that make it a compelling alternative in large environments in contrast to Nagios. &lt;br /&gt;
For visual notifications in desktop, &lt;a href=&quot;https://nagstamon.ifw-dresden.de/&quot;&gt;Nagstamon&lt;/a&gt; is used that connects to a monitoring system (supports a wide variety of systems) and displays which services need attention (how many are in CRITICAL/WARNING state etc).  Here is a typical image on my work desktop:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://blog.tzermias.com/assets/nagstamon.png&quot; alt=&quot;Nagstamon&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That means that 10 services are in CRITICAL state and you should take care of them while 173 have set a warning.&lt;br /&gt;
You can move this widget anywhere on your desktop. By clicking to it, a screen with detailed information about states is shown.&lt;/p&gt;

&lt;p&gt;Despite the fact that Nagstamon is always present on my desktop, I would like this information to be available in my Tmux status line.&lt;br /&gt;
Most of my time, I am in a terminal trying to troubleshoot an issue. &lt;br /&gt;
The question here, is how to integrate this kind of information in the status line.&lt;br /&gt;
Towards this, I made a simple script that checks how many services are in CRITICAL, WARNING or UNKNOWN state and shows it in the status line. Below is the complete code&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;#!/bin/bash

CGI_URL=&amp;quot;https://server/icinga/cgi-bin&amp;quot;
USERNAME=&amp;quot;&amp;quot;
PASSWORD=&amp;quot;&amp;quot;


out=$(curl --silent -u $USERNAME:$PASSWORD &amp;quot;$CGI_URL/status.cgi?jsonoutput&amp;amp;servicestatustypes=28&amp;quot; |jq .status.service_status[].status 2&amp;gt;&amp;amp;1)

echo $out | awk  &amp;#39;BEGIN {RS=&amp;quot; &amp;quot;;d=0;c=0;u=0;w=0} 
/DOWN/ {d++} 
/CRITICAL/ {c++} 
/UNKNOWN/ {u++} 
/WARNING/ {w++} 

END {
if (d&amp;gt;0) printf d&amp;quot; &amp;quot;
if (c&amp;gt;0) printf &amp;quot;#[bg=red]&amp;quot;c&amp;quot; #[default]&amp;quot;
if (u&amp;gt;0) printf &amp;quot;#[bg=magenta]#[fg=black]&amp;quot;u&amp;quot; #[default]&amp;quot;
if (w&amp;gt;0) printf &amp;quot;#[bg=yellow]#[fg=black]&amp;quot;w&amp;quot; #[default]&amp;quot;
}&amp;#39;
&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/tzermias/e229ac1ab67d78e9071bec7c12885f0c.js&quot;&gt; &lt;/script&gt;

&lt;p&gt;The only requirement is the presence of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jq&lt;/code&gt; for JSON parsing. It is just a crude try. &lt;br /&gt;
In a nutshell it leverages JSON output provided by the Icinga Classic Web UI.  The parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;servicestatustypes=28&lt;/code&gt; in the request, tell Icinga to return services that are in one of the WARNING, UNKNOWN or CRITICAL states. &lt;br /&gt;
More info is provided in the documentation &lt;a href=&quot;https://www.icinga.com/docs/icinga1/latest/en/cgiparams.html&quot;&gt;here&lt;/a&gt;.  To use the script, simple change the variables &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$CGI_URL&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$USERNAME&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PASSWORD&lt;/code&gt; to match your Icinga monitoring server and you are ready to go.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://blog.tzermias.com/assets/icinga_status.png&quot; alt=&quot;icinga_status.sh&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The complete result is shown on the above image.&lt;br /&gt;
Feel free to comment below on how to improve it.&lt;/p&gt;

</description>
				<pubDate>Mon, 06 Nov 2017 00:00:00 +0000</pubDate>
				<link>https://blog.tzermias.com/2017/11/icinga-status/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/2017/11/icinga-status/</guid>
			</item>
		
			<item>
				<title>From Wordpress to Jekyll</title>
				<description>&lt;p&gt;When I finally decided to start my personal blog back in 2013, I choose Wordpress as its blogging engine. Despite the fact that there is a big hype with Wordpress right now, I decided that its time to move to a more simpler engine.&lt;br /&gt;
In this post, I will explain the reasons for moving from Wordpress to Jekyll and describe my migration experience.&lt;/p&gt;

&lt;h2 id=&quot;wordpress&quot;&gt;Wordpress&lt;/h2&gt;
&lt;p&gt;Wordpress is one of the top-3 platforms to choose (the other two are Joomla and Drupal) when it comes to develop a new website.&lt;br /&gt;
It has a strong community of developers, a multitude of plugins to add functionality to your website (from photo sliders to more sophisticated plugins like Wordfence) and many web developers around the world use it as the basis for their end-products.&lt;br /&gt;
In my experience with Wordpress, I wouldn’t say that it suits me pretty well. The &lt;a href=&quot;https://en.wikipedia.org/wiki/WYSIWYG&quot;&gt;WYSIWYG&lt;/a&gt; interface always puzzles me and it hinders me from writing. Hence, I prefer a more simpler editor.&lt;br /&gt;
Of course, Wordpress has support for &lt;a href=&quot;https://wordpress.org/plugins/wp-markdown-editor/&quot;&gt;Markdown&lt;/a&gt; (that I am currently using to write this post), but for a couple of reasons I couldn’t use this option.&lt;br /&gt;
Another reason was that Wordpress, like any other CMS, needs regular updates both in its core and on its plugins. Wordpress has done great steps on improving its stability and security on its core. But when it comes to its themes or plugins, things are not the same.&lt;br /&gt;
Many users dread to update to a new version of a theme with the fear of breaking the entire site. The same lies to plugins, plus some of them are prone to vulnerabilities (remember the &lt;a href=&quot;https://blog.sucuri.net/2014/12/revslider-vulnerability-leads-to-massive-wordpress-soaksoak-compromise.html&quot;&gt;RevSlider&lt;/a&gt; vulnerability back in late 2014?).&lt;br /&gt;
Along with some minor limitations that my Wordpress installation had (that could be resolved with some effort), I decided I need a simpler engine for my blog.&lt;br /&gt;
Hence, I chose Jekyll. Besides, I thought that would be interesting to tackle with something new and I had a hunch that Jekyll would be better for me.&lt;/p&gt;

&lt;h2 id=&quot;jekyll&quot;&gt;Jekyll&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt;, is a static site generator written in Ruby. It uses a simple template to convert posts in text files to a complete site with links.&lt;br /&gt;
Jekyll is widely used and it is incorporated in Github Pages as its rendering engine. No database is required, just some files representing your posts.&lt;br /&gt;
The basic workflow for writing a post to Jekyll is the following; Open your favorite text editor, write your post (for example in Markdown), generate your entire site using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll build&lt;/code&gt; and upload the generated content to the document root of your site.&lt;br /&gt;
Jekyll functionality can be extended with the use of &lt;a href=&quot;https://jekyllrb.com/docs/plugins/&quot;&gt;plugins&lt;/a&gt;, so Jekyll can be tailored to your needs.&lt;br /&gt;
Jekyll has a great &lt;a href=&quot;https://jekyllrb.com/docs/home/&quot;&gt;documentation&lt;/a&gt; to start with. You can also watch some introductory tutorials and casts in &lt;a href=&quot;http://jekyll.tips/&quot;&gt;jekyll.tips&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The fact that posts are flat files gives you the opportunity to track changes using a Versioning Control System (VCS), like Git. This eliminates (up to a point) the need of regular backups to your site.&lt;br /&gt;
If something happens, you can re-render it and upload it again. Just ensure that VCS repo is replicated, by maintaining a remote copy in e.g GitHub or BitBucket. &lt;br /&gt;
Jekyll offers a simple web-server out-of-the-box, to test your changes. Type &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll serve&lt;/code&gt; inside your Jekyll directory and visit the generated site on your browser at &lt;a href=&quot;http://127.0.0.1:4000&quot;&gt;http://127.0.0.1:4000&lt;/a&gt;.&lt;br /&gt;
This test environment is great for testing new layouts, themes without the hassle of configuring a full-blown web server on your PC. You are just a command away to see how your site will look like!&lt;br /&gt;
You can write posts without the need to be online (OK, with the ubiquity of Internet connectivity nowadays this isn’t much of a strong argument), not to mention the potential of testing new layouts and writing posts in different branches in Git, without touching the live site.&lt;br /&gt;
Another advantage of Jekyll lies to its static nature; A page or a post in Jekyll is generated during &lt;em&gt;build&lt;/em&gt;. In contrast, dynamic websites generate a post or a page during &lt;em&gt;visit&lt;/em&gt;. &lt;br /&gt;
This of course induces a small delay of running the PHP script that connects to the database server, performs the appropriate queries to fetch the post and renders the HTML output during each visit.&lt;br /&gt;
Despite the fact that this delay is usually small (and sometimes negligible), it can increased when for instance the query on the database is taking a couple of seconds (either due to load on the database server or due to the fact that the database itself doesn’t have proper indexing on its tables).&lt;/p&gt;

&lt;h2 id=&quot;migration-process&quot;&gt;Migration process&lt;/h2&gt;
&lt;p&gt;After reasoning about my choice on Jekyll, its time to perform the actual migration from Wordpress. &lt;br /&gt;
Jekyll has a built-in mechanism for the migration from various platforms. You can find more details on the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jekyll-import&lt;/code&gt; &lt;a href=&quot;https://import.jekyllrb.com/docs/&quot;&gt;documentation&lt;/a&gt;.&lt;br /&gt;
But first, lets create a Jekyll instance.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;jekyll new myblog&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This command will create the basic structure of a Jekyll site inside the directory &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;myblog&lt;/code&gt;. If we just want to see it, just type;&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;jekyll serve &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The check the result at &lt;a href=&quot;http://127.0.0.1:4000&quot;&gt;http://127.0.0.1:4000&lt;/a&gt;. It is just a simple site.&lt;br /&gt;
To perform the actual migration from my Wordpress, I used the “Export” option, located in My Site → Settings. For the lazy, just go to http://mysite.com/wp-admin/export.php . &lt;br /&gt;
This generates an XML file with the entire content of your site. It is widely used from migrations between Wordpress installations from different providers.&lt;br /&gt;
The import of your data to Jekyll, is performed using the following command.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;ruby &lt;span class=&quot;nt&quot;&gt;-rubygems&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;require &quot;jekyll-import&quot;;
    JekyllImport::Importers::WordpressDotCom.run({
      &quot;source&quot; =&amp;gt; &quot;wordpress.xml&quot;,
      &quot;no_fetch_images&quot; =&amp;gt; false,
      &quot;assets_folder&quot; =&amp;gt; &quot;assets&quot;
    })&apos;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;This eventually will parse &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;wordpress.xml&lt;/code&gt; file that was exported from Wordpress, download any image contained on posts and save it to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;assets&lt;/code&gt; folder. &lt;br /&gt;
You can find more information in the &lt;a href=&quot;https://import.jekyllrb.com/docs/wordpressdotcom/&quot;&gt;Wordpress&lt;/a&gt; section of the documentation.&lt;br /&gt;
If no errors are presented, the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; directory (the directory that contains the actual posts of your site), would have the following structure:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; _posts
total 88
&lt;span class=&quot;nt&quot;&gt;-rw-rw-r--&lt;/span&gt; 1 aris aris  402 Dec  7 16:15 2013-11-29-hello-world-2.html
&lt;span class=&quot;nt&quot;&gt;-rw-rw-r--&lt;/span&gt; 1 aris aris 3756 Dec  7 16:15 2014-10-31-busybox-sagem-routers.html
&lt;span class=&quot;nt&quot;&gt;-rw-rw-r--&lt;/span&gt; 1 aris aris 4861 Dec  7 16:15 2016-01-26-migrating-to-qemu.html
&lt;span class=&quot;nt&quot;&gt;-rw-rw-r--&lt;/span&gt; 1 aris aris 3144 Dec  7 16:15 2016-06-28-disk-replacement-notes.html
&lt;span class=&quot;nt&quot;&gt;-rw-rw-r--&lt;/span&gt; 1 aris aris 2694 Dec  7 16:15 2016-07-05-a-simple-reminder-in-ubuntu.html
&lt;span class=&quot;nt&quot;&gt;-rw-rw-r--&lt;/span&gt; 1 aris aris 2114 Dec  7 16:15 2016-07-26-create-a-vm-with-virt-install-with-no-hassle.htm&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;As simple as that!&lt;/p&gt;

&lt;p&gt;In this blog, I used the &lt;a href=&quot;https://github.com/streetturtle/jekyll-clean-dark&quot;&gt;Jekyll Clean Dark&lt;/a&gt; theme from &lt;a href=&quot;http://pavelmakhov.com&quot;&gt;Pavel Makhov&lt;/a&gt; and just added my &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; director.&lt;br /&gt;
I performed a couple of minor modifications to the posts (e.g replaced &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;code&amp;gt;&lt;/code&gt; tags with Jekyll highlighting), and deployed the site to the server.&lt;br /&gt;
The site is currently served entirely from Nginx (hence leveraging HTTP/2) and its main page loads in slightly more that 1.5 seconds. Not so bad!&lt;/p&gt;

&lt;p&gt;All things considered, I think that Jekyll suits me better. I can continue to use tools like git, vim etc. rather than visiting a page with an editor.&lt;br /&gt;
Nevertheless, I still do consider Wordpress as an excellent blog engine and CMS in general, but somehow it doesn’t suits me. But that’s just me!&lt;/p&gt;
</description>
				<pubDate>Wed, 07 Dec 2016 00:00:00 +0000</pubDate>
				<link>https://blog.tzermias.com/2016/12/from-wordpress-to-jekyll/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/2016/12/from-wordpress-to-jekyll/</guid>
			</item>
		
			<item>
				<title>Create a VM with virt-install with no hassle</title>
				<description>&lt;p&gt;Occasionally, I come to the point where I need to create a Virtual Machine for testing purposes. Either, to check something new (a new version of Plesk or cPanel, for instance) or just create a test environment for my Ansible playbooks. Virtualbox has been removed from my computer completely, in favour of QEMU/KVM. Despite the fact that you can use a GUI application like &lt;code&gt;virt-manager&lt;/code&gt; (similar to VirtualBox GUI) to create a VM in KVM, I would prefer a more automated way of creating one.&lt;/p&gt;

&lt;p&gt;The only prerequisite that I put on this, is that VM creation and installation must be unattended.&lt;br /&gt;
I resort to &lt;code&gt;virt-install&lt;/code&gt;, part of &lt;code&gt;virtinst&lt;/code&gt; package in Ubuntu. Thus, we end up with the following:&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;virt-install &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; centos-test &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; 768 &lt;span class=&quot;nt&quot;&gt;--vcpus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2 &lt;span class=&quot;nt&quot;&gt;--os-variant&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;rhel7 &lt;span class=&quot;nt&quot;&gt;--accelerate&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;network&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;default &lt;span class=&quot;nt&quot;&gt;--disk&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/disk.img,size&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;4.5 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; ftp://ftp.cc.uoc.gr/CentOS/7.2.1511/os/x86_64/ &lt;span class=&quot;nt&quot;&gt;--nographics&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;ks=http://192.168.122.1:8000/ks.cfg console=ttyS0&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;p&gt;The above command creates a new Virtual Machine, named &quot;centos-test&quot;, uses a CentOS 7 local mirror (here ftp.cc.uoc.gr) as its installation source, creates (if it does not exist) a new disk with size 4.5 GiB and installs CentOS 7 using ks.cfg kickstart file. Note that kickstart is served from a web server in 192.168.122.1, the IP address of the host when you use the default NAT configuration. In case you don&apos;t have a webserver in handy, you can start the simplest one, just by typing &lt;code&gt;python -m SimpleHTTPServer&lt;/code&gt; in a different console window. A ks.cfg that I use is available on GitHub, &lt;a href=&quot;https://gist.github.com/tzermias/bee4a0ebe9e4b1042b6b0eaf5a97913b&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
				<pubDate>Tue, 26 Jul 2016 09:04:28 +0000</pubDate>
				<link>https://blog.tzermias.com/virtualization/create-a-vm-with-virt-install-with-no-hassle/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/virtualization/create-a-vm-with-virt-install-with-no-hassle/</guid>
			</item>
		
			<item>
				<title>A simple reminder in Ubuntu</title>
				<description>&lt;p&gt;As far as I know Ubuntu does not have a built-in reminder application. Surely there are some third-party applications that do the job well, but I didn&apos;t want to install extra packages etc.&lt;br /&gt;
So, I tried to build mine!&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;This reminder is based on &lt;em&gt;at(1)&lt;/em&gt; command, that allows you to run a
command at specified time.&lt;br /&gt; In case it has not been installed on your
system, just install it via:&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;at&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;em&gt;at&lt;/em&gt; reads commands from standard input, so it is handy in case where we
need an one-liner. For example the above command&lt;br /&gt; 
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;firefox&quot;&lt;/span&gt; | at now + 1 minute&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
starts Firefox after one minute. You can
find more examples in the following &lt;a
href=&quot;http://www.computerhope.com/unix/uat.htm&quot;&gt;link&lt;/a&gt;.&lt;/p&gt; &lt;p&gt;So, we found a
way to schedule one-time jobs but how are going to be notified?&lt;br /&gt;
&lt;em&gt;notify-send&lt;/em&gt; to the rescue. This simple program sends notifications to
the user via command line. 
For example the following&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;notify-send &lt;span class=&quot;s2&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;br /&gt;
shows this notification on the desktop!&lt;br /&gt; 
&lt;a href=&quot;/assets/hello-world.png&quot;&gt;&lt;img
	class=&quot;alignnone size-medium wp-image-65&quot; src=&quot;/assets/hello-world-300x96.png&quot; alt=&quot;hello-world&quot; width=&quot;300&quot;
						     height=&quot;96&quot; /&gt;&lt;/a&gt;
&lt;br /&gt; 
Notifications are fully customizable: You can set summary, body or add an image to your
notification. Just &lt;em&gt;man
notify-send&lt;/em&gt; for more information.&lt;/p&gt; &lt;p&gt;So with these two pieces, we can
create the following bash function and incorporate it on our &lt;em&gt;.bashrc&lt;/em&gt;
file:&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;notifymeat&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;notify-send -i /path/to/image.png &quot;Impossible Mission robot&quot; &apos;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | at &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;br /&gt; If we run the following&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;notifymeat &lt;span class=&quot;s2&quot;&gt;&quot;now +1 minute&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;br /&gt; this notification will appear on
your screen&lt;br /&gt; &lt;a
	   href=&quot;/assets/hello-world2.png&quot;&gt;&lt;img
	class=&quot;alignnone size-medium wp-image-67&quot; src=&quot;/assets/hello-world2-300x113.png&quot; alt=&quot;hello-world2&quot; width=&quot;300&quot;
	height=&quot;113&quot; /&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The name as well as the image of the pop-up
window are from the infamous &quot;Impossible Mission&quot; game in Commodore 64.&lt;/p&gt;
</description>
				<pubDate>Tue, 05 Jul 2016 08:41:17 +0000</pubDate>
				<link>https://blog.tzermias.com/linux/a-simple-reminder-in-ubuntu/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/linux/a-simple-reminder-in-ubuntu/</guid>
			</item>
		
			<item>
				<title>Disk replacement notes</title>
				<description>&lt;p&gt;Recently, I bought a Samsung 850 Evo 500 GB SSD drive, as an upgrade to my
Thinkpad X220. This post is yet another post of installing and aligning SSD
partitions in ext4 filesystems. 
&lt;!--more--&gt;
I have followed &lt;a
href=&quot;https://www.void.gr/kargig/blog/2012/01/11/linux-ssd-partition-alignment-tips/&quot;&gt;kargig&apos;s
post&lt;/a&gt; on installing and aligning his SSD. This is simply a bunch of notes I
kept during the procedure and not an explanatory post.&lt;/p&gt; &lt;p&gt;Before you start,
you must find the Erase Block Size and Page size of the SSD. With a couple of
searches in Google, I discovered that Samsung 850 EVO has the following
values:&lt;br /&gt;
Erase Block Size: 1536kb&lt;br /&gt;
Page size: 8kb&lt;/p&gt;
&lt;p&gt;I followed the same formula that kargig used to align the partitions. In my case, I used heads=96 and sectors=32&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;fdisk &lt;span class=&quot;nt&quot;&gt;-H96&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-S32&lt;/span&gt; /dev/sdb&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;The next step is to align the LVM accordingly.&lt;br /&gt;
Create a physical volume aligned to the Erase Block Size using the command&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;pvcreate &lt;span class=&quot;nt&quot;&gt;--dataalignment&lt;/span&gt; 1536k /dev/sdb2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;br /&gt;
Then check the alignment of the physical volume:&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;pvs /dev/sdb2 &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt;+pe_start&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;br /&gt;
The output of this command should be something like this&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;PV VG Fmt Attr PSize PFree 1st PE
/dev/sdb2 thinkpad lvm2 a-- 465,26g 0 1,50m&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;br /&gt;
Note that the &lt;em&gt;1st PE&lt;/em&gt; starts from 1536k(1,50m), which is our goal here. Then proceed to create the VG and LVs you need:&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;vgcreate thinkpad /dev/sdb2
lvcreate &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt; 4G &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; swap thinkpad
lvcreate &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; 100%FREE &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; root thinkpad&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;To align the ext4 partition, you have to set the proper values on &lt;em&gt;stripe-width&lt;/em&gt; and &lt;em&gt;stride&lt;/em&gt; options. I followed &lt;a href=&quot;https://thelastmaimou.wordpress.com/2013/05/04/magic-soup-ext4-with-ssd-stripes-and-strides/&quot;&gt;this&lt;/a&gt; recipe. In a nutshell:&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;stride = Page size / Filesystem block&lt;br /&gt;
stripe-width = Erase Block / Filesystem block&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;Filesystem block is 4kB (or 4096 bytes), so stride = 8 kB/4 kB = &lt;strong&gt;2 kB&lt;/strong&gt; and stripe-width=1536 kB /4 kB = 384 kB.&lt;br /&gt;
We create the ext4 partition using this command:&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;mkfs.ext4 &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt; 4096 &lt;span class=&quot;nt&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;stride&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;2,stripe-width&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;384 /dev/mapper/thinkpad-root&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;The last step is to copy data from the HDD to the SSD and change /etc/fstab on the SSD&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /mnt/ssd
mount /dev/thinkpad/root /mnt/ssd/
&lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; /mnt/ssd/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;dev,proc,sys,mnt&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-avp&lt;/span&gt; /dev/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;console,random,urandom,zero&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; /mnt/ssd/dev/
rsync &lt;span class=&quot;nt&quot;&gt;-aPEHv&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--exclude&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev &lt;span class=&quot;nt&quot;&gt;--exclude&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/proc &lt;span class=&quot;nt&quot;&gt;--exclude&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/sys &lt;span class=&quot;nt&quot;&gt;--exclude&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/mnt &lt;span class=&quot;nt&quot;&gt;--exclude&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/var/cach/apt/archives/ /mnt/ssd
vi /mnt/ssd/etc/fstab &lt;span class=&quot;c&quot;&gt;#Update /etc/fstab with the UUID of the root partition.&lt;/span&gt;
update-grub&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/p&gt;
</description>
				<pubDate>Tue, 28 Jun 2016 08:43:19 +0000</pubDate>
				<link>https://blog.tzermias.com/linux/disk-replacement-notes/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/linux/disk-replacement-notes/</guid>
			</item>
		
			<item>
				<title>Migrating to QEMU</title>
				<description>&lt;p&gt;I use virtualization for various tasks. Either for running photo-editing
software in Windows or just run a test CentOS in a safe environment. But for
quite a while, for all of my virtualization chores, Virtualbox was the answer
when you need something that works really quick. VM management is very easy and
you could deploy a VM within seconds. 
Despite the fact that I use it flawlessly
for years, I was tricked into migrating to QEMU. I thought that it is
interesting to write down my experience.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;The goal was to migrate my
existing Windows 7 VM to a QEMU, without compromises in usability and without
(extensively) modifying the image. Moreover I wanted to tackle with some KVM
features (like memory ballooning). For some people it seems more reasonable to
perform a clean Windows installation, rather to struggle migrating an existing
one. I chose the hard way, because of fun primarily and I didn&apos;t want to
reinstall programs from scratch, customize it etc.&lt;/p&gt;
&lt;p&gt;Before migrating, make sure you have the required packages for QEMU and
KVM:&lt;br /&gt;  
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;qemu qemu-system-x86_64 qemu-kvm&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;The first step for the migration is to convert the Virtualbox VDI image into raw format. This can be performed using the following command:&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;VBoxManage clonehd &lt;span class=&quot;nt&quot;&gt;--format&lt;/span&gt; raw /path/to/WindowsVM.vdi
/path/to/WindowsVM.raw&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;As the disk image is cloned, the free space in your disk should be at least
the size of the VM. Let&apos;s say the image is 30 GB, you will need at least 30 GB
of free space in order the conversion to be successful. Furthermore, cloning
takes a considerable amount of time, so be patient.&lt;br /&gt; Upon successful
conversion, I tried to run the image with QEMU and no special arguments.&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;qemu-system-x86_64 &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 1024M /path/to/WindowsVM.raw&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;br /&gt;
The -m 1024 specifies the amount of memory that the VM should have. The result
in my case was a BSOD! &lt;/p&gt; &lt;p&gt;Let&apos;s try to run it with KVM support&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;qemu-system-x86_64 &lt;span class=&quot;nt&quot;&gt;--enable-kvm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 1024M &lt;span class=&quot;nt&quot;&gt;-boot&lt;/span&gt; c /path/to/WindowsVM.raw&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;br /&gt; Here, the VM started successfully, despite
the fact that it was a bit slow. Hence, I download the &lt;a
href=&quot;https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso&quot;
target=&quot;_blank&quot;&gt;VirtIO drivers ISO&lt;/a&gt; and mount it in the VM. Let&apos;s start the
VM again with virtio network and virtio disk to see what happens.&lt;br /&gt;
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;qemu-system-x86_64 &lt;span class=&quot;nt&quot;&gt;--enable-kvm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 1024M  &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; nic,model&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; user &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-boot&lt;/span&gt; c &lt;span class=&quot;nt&quot;&gt;-drive&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/WindowsVM.raw,if&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;br /&gt; This resulted
in a BSOD again, as the VirtIO disk driver was not actually installed. The
solution was found in &lt;a
href=&quot;https://wiki.archlinux.org/index.php/QEMU#Change_Existing_Windows_VM_to_use_virtio&quot;
target=&quot;_blank&quot;&gt;Archlinux wiki&lt;/a&gt;. You need to make a &quot;dumb&quot; image and boot
the VM with that.
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;dd &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/dev/zero &lt;span class=&quot;nv&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;dumb.file &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1M &lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;100
qemu-system-x86_64 &lt;span class=&quot;nt&quot;&gt;--enable-kvm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 1024M  &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; nic,model&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; user &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-cdrom&lt;/span&gt; /path/to/virtio-win-0.1.102.iso &lt;span class=&quot;nt&quot;&gt;-boot&lt;/span&gt; c &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-drive&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/dumb.file,if&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio /path/to/WindowsVM.raw&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
&lt;br /&gt; As stated in the Archlinux wiki, Windows will detect the dumb
image as a new device and will try to find a driver. Go to Control Panel &amp;gt;
Device Management, detect the &quot;Unknown device&quot; and Install the VirtIO SCSI
driver from the virtio-win iso. Then shutdown the VM, and boot it with virtio
support:
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;qemu-system-x86_64 &lt;span class=&quot;nt&quot;&gt;--enable-kvm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 1024M  &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; nic,model&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; user &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-boot&lt;/span&gt; c &lt;span class=&quot;nt&quot;&gt;-drive&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/WindowsVM.raw,if&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
Works flawlessly!&lt;/p&gt; &lt;p&gt;Another feature I would like to tackle with, was memory
ballooning. In short, you can change the VM memory on the fly, without
rebooting it. More information for this feature is available on the &lt;a
href=&quot;http://www.linux-kvm.org/page/Projects/auto-ballooning&quot;
target=&quot;_blank&quot;&gt;linux-kvm.org&lt;/a&gt; page.&lt;br /&gt; 
&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;qemu-system-x86_64 &lt;span class=&quot;nt&quot;&gt;--enable-kvm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; 1024M  &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; nic,model&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio &lt;span class=&quot;nt&quot;&gt;-net&lt;/span&gt; user &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;-boot&lt;/span&gt; c &lt;span class=&quot;nt&quot;&gt;-drive&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/path/to/WindowsVM.raw,if&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;virtio &lt;span class=&quot;nt&quot;&gt;-balloon&lt;/span&gt; virtio&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
When run,
the Windows VM, will detect the balloon device and will install the respective
driver.&lt;br /&gt; You can change the memory size from the QEMU monitor (press
Ctrl+Alt+2) using the command &quot;balloon&quot;. Then run &quot;info balloon&quot; to list its
current status.&lt;/p&gt; &lt;p&gt;Hope this information will help you perform a migration
from Virtualbox to QEMU/KVM without a hassle!&lt;/p&gt;
</description>
				<pubDate>Tue, 26 Jan 2016 10:22:19 +0000</pubDate>
				<link>https://blog.tzermias.com/linux/migrating-to-qemu/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/linux/migrating-to-qemu/</guid>
			</item>
		
			<item>
				<title>Busybox access on Sagem F@ST 2404 routers</title>
				<description>&lt;p&gt;I stumbled accross a Sagem F@ST 2404 ADSL modem recently. While I was experimenting with some of its features, I found an interesting feature (or a bug :P) in version 3.21a4&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Usually, many home ADSL modems provide command line access (usually via telnet) along with their fancy Web interface.&lt;br /&gt;
If you try to connect via telnet to ths ADSL modem, you will be provided with the follwing screen of options:&lt;br /&gt;
&lt;a href=&quot;/assets/router.png&quot;&gt;&lt;img src=&quot;/assets/router-300x105.png&quot; alt=&quot;router&quot; width=&quot;300&quot; height=&quot;105&quot; class=&quot;alignnone size-medium wp-image-23&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So you just type an appropriate number and navigate to the respective subcategory.&lt;br /&gt;
But what if you try to type a command instead of a number? Let&apos;s try with &lt;code&gt;ls /bin&lt;/code&gt; first.&lt;br /&gt;
&lt;a href=&quot;/assets/2014-10-31-104845.png&quot;&gt;&lt;img src=&quot;/assets/2014-10-31-104845.png&quot; alt=&quot;ls&quot; width=&quot;212&quot; height=&quot;79&quot; class=&quot;alignnone size-full wp-image-24&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nope. Let&apos;s try with a simple &lt;code&gt;echo &quot;This is a test&quot;&lt;/code&gt; or something similar.&lt;br /&gt;
&lt;a href=&quot;/assets/2014-10-31-105121.png&quot;&gt;&lt;img src=&quot;/assets/2014-10-31-105121.png&quot; alt=&quot;test&quot; width=&quot;207&quot; height=&quot;67&quot; class=&quot;alignnone size-full wp-image-25&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Bingo! That means that command line interface does not sanitize input properly and allows the user to execute arbitrary commands!&lt;br /&gt;
Let&apos;s incorporate our command a bit. Let&apos;s try to invoke &lt;code&gt;busybox sh&lt;/code&gt;&lt;br /&gt;
&lt;a href=&quot;/assets/2014-10-31-105427.png&quot;&gt;&lt;img src=&quot;/assets/2014-10-31-105427.png&quot; alt=&quot;Στιγμιότυπο από 2014-10-31 10:54:27&quot; width=&quot;192&quot; height=&quot;67&quot; class=&quot;alignnone size-full wp-image-26&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nope! Let&apos;s try to combine the last two commands to a single one and see the result. So our new command would be&lt;code&gt;echo &quot;This is a test&quot;; busybox sh&lt;/code&gt;&lt;br /&gt;
&lt;a href=&quot;/assets/2014-10-31-105709.png&quot;&gt;&lt;img src=&quot;/assets/2014-10-31-105709.png&quot; alt=&quot;busybox&quot; width=&quot;300&quot; height=&quot;93&quot; class=&quot;alignnone size-medium wp-image-27&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The busybox shell is spawned! Great!&lt;br /&gt;
You can explore you router internals via typical &lt;code&gt;ls&lt;/code&gt; and &lt;code&gt;cat&lt;/code&gt; commands. You can also view running processes using &lt;code&gt;ps &lt;/code&gt; command.&lt;br /&gt;
Be careful not to run the &lt;code&gt;cfm&lt;/code&gt; executable! I speculate that this is the router&apos;s bootstrap script and if you try to re-execute, you will probably lose connectivity. In that case just try a hardware reboot of the router. &lt;/p&gt;
</description>
				<pubDate>Fri, 31 Oct 2014 09:07:26 +0000</pubDate>
				<link>https://blog.tzermias.com/uncategorized/busybox-sagem-routers/</link>
				<guid isPermaLink="true">https://blog.tzermias.com/uncategorized/busybox-sagem-routers/</guid>
			</item>
		
	</channel>
</rss>
