<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://notes.aflukasz.pl/en</id>
  <title>notes - aflukasz - EN</title>
  <link href="https://notes.aflukasz.pl/en"/>
  <link rel="self" href="https://notes.aflukasz.pl/en/feed.xml"/>
  <author><name>notes.aflukasz.pl</name></author><updated>2025-08-09T00:00:00+00:00</updated>
  <entry>
    <title>Revisiting pg_dump data ordering</title>
    <link href="https://notes.aflukasz.pl/en/2025/08/09/pg-dump-order-revisited"/>
    <id>https://notes.aflukasz.pl/en/2025/08/09/pg-dump-order-revisited</id>
    <published>2025-08-09T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/08/09/pg-dump-order-revisited">

&lt;p&gt;Many, MANY years ago - more than I would like to admit - I was one of the people
answering this particular
&lt;a href=&#34;/en/2010/08/10/pg-dump-order&#34;&gt;Stack Overflow question about the order of data in the output of pg_dump&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In my answer I was pointing out then-recent &lt;a href=&#34;http://archives.postgresql.org/pgsql-hackers/2010-04/msg00710.php&#34;&gt;patch to pg_dump&lt;/a&gt; that was providing the &lt;code&gt;--ordered&lt;/code&gt; param that would cause
dumping of the table data in a deterministic order, instead of reflecting the
current on-disk structure of the table.&lt;/p&gt;
&lt;p&gt;That patch did not gain enough traction and was not accepted into the code
base. And as far as I can see, no addition of this kind was made since then.&lt;/p&gt;
&lt;p&gt;I&#39;m revisiting this topic today by accident. But, by a funny coincidence,
tomorrow, to the day, is the anniversary of that Stack Overflow answer, and, by
another coincidence, I &lt;em&gt;could&lt;/em&gt; have recalled this just a few weeks ago, when I
was testing PostgreSQL instance migration (and comparing two &lt;code&gt;pg_dump&lt;/code&gt; outputs
- dealing with this exact ordering issue).&lt;/p&gt;
&lt;p&gt;So just as a quick reminder and a demonstration - if we run this...&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;psql -tAc &#34;select version()&#34;

# Enter test data
psql -c &#34;drop table if exists test; create table test (a int); insert into test (a) values (1), (2)&#34;

# Compare two dumps
echo &#34;-- diff 1 --&#34;
diff &amp;lt;(pg_dump) &amp;lt;(pg_dump)

# Compare two dumps after updating the first tuple
BEFORE=&#34;$(pg_dump)&#34;
psql -c &#34;update test set a = 1 where a = 1&#34;
echo &#34;-- diff 2 --&#34;
diff -c1  &amp;lt;(echo &#34;$BEFORE&#34;) &amp;lt;(pg_dump)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... the result will be:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;PostgreSQL 17.5 on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14+deb12u1) 12.2.0, 64-bit
DROP TABLE
CREATE TABLE
INSERT 0 2
-- diff 1 --
UPDATE 1
-- diff 2 --
*** /dev/fd/63  Sat Aug  9 13:57:57 2025
--- /dev/fd/62  Sat Aug  9 13:57:57 2025
***************
*** 39,42 ****
  COPY public.test (a) FROM stdin;
- 1
  2
  \.
--- 39,42 ----
  COPY public.test (a) FROM stdin;
  2
+ 1
  \.
***************
*** 47 ****
--- 47,48 ----
  --
+
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The UPDATE of the row with &#34;1&#34; caused its tuple to now be located after the one
with row containing &#34;2&#34;, and our &lt;code&gt;pg_dump&lt;/code&gt; output changed accordingly.&lt;/p&gt;
&lt;p&gt;As a side note: here we also see that an &lt;code&gt;UPDATE&lt;/code&gt; that does not change the actual
row values is still generating a new physical tuple. This is worth knowing on
its own.&lt;/p&gt;
&lt;p&gt;For my recent use case, comparing &lt;code&gt;pg_dump&lt;/code&gt; outputs was just an extra
sanity check of the migration process, so simply sorting the output files
themselves, and getting empty diff as a result, was good enough.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Nature of Ansible's "Timeout (12s) waiting for privilege escalation prompt" error</title>
    <link href="https://notes.aflukasz.pl/en/2025/08/01/ansible-12s-timeout"/>
    <id>https://notes.aflukasz.pl/en/2025/08/01/ansible-12s-timeout</id>
    <published>2025-08-01T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/08/01/ansible-12s-timeout">

&lt;p&gt;Ansible can occasionally fail with the following error: &#34;Timeout (12s) waiting for privilege escalation prompt&#34;.&lt;/p&gt;
&lt;p&gt;At some point I wanted to finally learn &lt;em&gt;exactly&lt;/em&gt; what this &#34;privilege escalation prompt
timeout&#34; is, where I can change its value and where it says that it
defaults to 12 seconds.&lt;/p&gt;
&lt;p&gt;Clearly it relates to &lt;code&gt;sudo&lt;/code&gt; (or other &lt;code&gt;become&lt;/code&gt; mechanism), but I could not
find anything about it in Ansible documentation - nothing about such specific
timeout. In fact, &lt;strong&gt;it seemed that there is no setting in Ansible as a whole
with a default value of 12 seconds &lt;em&gt;at all&lt;/em&gt;&lt;/strong&gt;. And I did not have any such value set anywhere on
my side, too.&lt;/p&gt;
&lt;h1&gt;Inspecting Ansible source&lt;/h1&gt;
&lt;p&gt;Luckly, searching Ansible source code for the
&lt;a href=&#34;https://github.com/ansible/ansible/blob/v2.19.0/lib/ansible/plugins/connection/ssh.py#L1245&#34;&gt;exact place where this error originates from&lt;/a&gt;
turned out to be trivial:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ git log -1 --pretty=oneline
82529e534dd3edd84aba03d86b337f88c58b9982 (HEAD, tag: v2.19.0) New release v2.19.0 (#85513)

$ grep -Rn &#34;waiting for privilege escalation prompt&#34; lib/
lib/ansible/plugins/connection/ssh.py:1245:                        raise AnsibleConnectionFailure(&#39;Timeout (%ds) waiting for privilege escalation prompt: %s&#39; % (timeout, to_native(b_stdout)))

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From there it&#39;s easy to track down the whole context that is important here.
First we have the code that starts &lt;code&gt;ssh&lt;/code&gt; in a subprocess (with a proper &lt;a href=&#34;https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ssh_connection.html#parameter-timeout&#34;&gt;connection timeout&lt;/a&gt;
passed as an argument, e.g. as &lt;code&gt;-o ConnectTimeout&lt;/code&gt; to openssh client):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-p&#34;&gt;p = subprocess.Popen(...)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we construct the timeout value the we discuss in this note:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# select timeout should be longer than the connect timeout, otherwise
# they will race each other when we can&#39;t connect, and the connect
# timeout usually fails
timeout = 2 + self.get_option(&#39;timeout&#39;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And we use it just a moment later, when we wait for data from the connection:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;selector = selectors.DefaultSelector()
selector.register(p.stdout, selectors.EVENT_READ)
selector.register(p.stderr, selectors.EVENT_READ)

...

while True:
    poll = p.poll()
    events = selector.select(timeout)

    # We pay attention to timeouts only while negotiating a prompt.

    if not events:
        # We timed out
        if state &amp;lt;= states.index(&#39;awaiting_escalation&#39;):
            # If the process has already exited, then it&#39;s not really a
            # timeout; we&#39;ll let the normal error handling deal with it.
            if poll is not None:
                break
            self._terminate_process(p)
            raise AnsibleConnectionFailure(&#39;Timeout (%ds) waiting for privilege escalation prompt: %s&#39; % (timeout, to_native(b_stdout)))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The two key things to note here are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The value of 12 seconds mentioned in the title,
which is used as a timeout for reaching privilege escalation
prompt, comes from the value of &lt;a href=&#34;https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ssh_connection.html#parameter-timeout&#34;&gt;SSH connection timeout&lt;/a&gt; (which defaults to 10 seconds) extended by hardcoded
extra 2 seconds.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Countdown for both timeouts (connection and reaching privilege escalation prompt)
is started approximately at the same time - when connection initiation starts,
i.e. they more or less overlap (as opposed to prompt timeout starting
its countdown &lt;em&gt;after&lt;/em&gt; the connection is ready).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For defaults we have 10 seconds to connect to the host (timeout passed to the
&lt;code&gt;ssh&lt;/code&gt; process), and then we have all what is left from these 10 seconds, plus
extra 2 seconds, to reach privilege escalation prompt from the remote system
(assuming we requested such escalation).&lt;/p&gt;
&lt;h1&gt;Side note on these two extra seconds&lt;/h1&gt;
&lt;p&gt;It looks like this 2 seconds extension was &lt;a href=&#34;https://github.com/ansible/ansible/commit/5bd096208c6b451810d69e2541fe0fe8d8b32953&#34;&gt;added a long time ago (2015)&lt;/a&gt;, to avoid a situation where the
connection timeout managed by the &lt;code&gt;ssh&lt;/code&gt; process and the reaching-escalation-prompt
timeout managed inside the Python process would race each other upon slow
connection (or no connectivity at all) and then &lt;a href=&#34;https://github.com/ansible/ansible/issues/12916&#34;&gt;lead to other confusing error message&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Meaning that this extension is not motivated by wanting to have an extra time
to get to the escalation prompt after connecting, but is rather a trick to solve
different issue, with a side effect of having this one extra timeout value.&lt;/p&gt;
&lt;h1&gt;Conclusions&lt;/h1&gt;
&lt;p&gt;There is a dedicated timeout for obtaining privilege escalation prompt on the
host, &lt;strong&gt;but its value is an implementation detail and is not exposed to the user as a separate setting.&lt;/strong&gt; It&#39;s simply derived from &lt;a href=&#34;https://docs.ansible.com/ansible/latest/collections/ansible/builtin/ssh_connection.html#parameter-timeout&#34;&gt;SSH connection timeout&lt;/a&gt; by extending it by 2 seconds,
which, if default settings are used, results in the value of 12 seconds. At
the same time this value is present in the timeout error message, which may be
slightly confusing as to what is the exact nature of the timeout and its value.&lt;/p&gt;
&lt;p&gt;Changing the SSH connection timeout setting is the way to influence how long
Ansible will wait until triggering the timeout that generates the discussed
error.&lt;/p&gt;
&lt;p&gt;Slow connection process (taking substantial part of the connection timeout)
reduces time left for awaiting escalation prompt after connection succeeded.
On a heavy loaded systems this may trigger timeouts reported as &#34;Timeout (12s) waiting for privilege escalation prompt&#34;,
while the culprit may mostly come from some networking issues (as this reported
timeout overlaps the connection process).&lt;/p&gt;
&lt;p&gt;On the other hand, &#34;Timeout (12s) waiting for privilege escalation prompt&#34;,
may also mean that &lt;code&gt;ssh&lt;/code&gt; connection succeeded with some delay, and yes it&#39;s
the host that is not too responsive, but it does not mean we have spent the whole
12 seconds between connection being established and us stopping awaiting for the
prompt - it might as well be, say, half that time (rest being used up during the
connection process).&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Explicit empty <code>else</code> branches in templated configs</title>
    <link href="https://notes.aflukasz.pl/en/2025/07/22/explicit-else-config-templates"/>
    <id>https://notes.aflukasz.pl/en/2025/07/22/explicit-else-config-templates</id>
    <published>2025-07-22T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/07/22/explicit-else-config-templates">

&lt;p&gt;Examples in this entry use Jinaj2 syntax, but the topic is completely stack
agnostic and does not require deep understanding of any specific templating
language.&lt;/p&gt;
&lt;h1&gt;Problem statement&lt;/h1&gt;
&lt;p&gt;When templating config files, it&#39;s not uncommon that one ends up with some
form of the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-jinja2&#34;&gt;{% if something %}

    some-config-statement

{% endif %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s a conditionally added statement, so not just a config param that we would
assign on/off value, but rather something that we want to either be present or
be completely skipped - maybe absence of this statement is the only state that
has semantics that we want, maybe we want to lean on a default behavior
hardcoded in the configured software etc.&lt;/p&gt;
&lt;p&gt;At a first glance there is not much to it. But, if we were to look at the
resulting config file, we will either see that the statement is set or... we
will see nothing (surrounded by the rest of the file).&lt;/p&gt;
&lt;p&gt;And while the existence of nothing can be argued (&lt;a href=&#34;https://www.youtube.com/watch?v=1OLz6uUuMp8&#34;&gt;2013 Isaac Asimov Memorial Debate: The Existence of Nothing &lt;/a&gt;),
it&#39;s of not much use for us here, because we will either not notice it when
later reading the resulting file, or we won&#39;t remember why it&#39;s there or what
it means, exactly, or if this is maybe some bug, missed decision about the
configuration state etc.&lt;/p&gt;
&lt;h1&gt;Improving the situation&lt;/h1&gt;
&lt;p&gt;What I often times find much more useful, is to make the else branch explicit
and put a comment there:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-jinja2&#34;&gt;{% if something %}

    some-config-statement

{% else %}

    # option disabled - skipping config lines for XXX

{% endif %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or maybe render skipped statements in a commented-out fashion:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-jinja2&#34;&gt;
{% if something %}

    some-config-statement

{% else %}

    # some-config-statement

{% endif %}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That way we make absence explicit and thus more clear outside of the context
of the template source and specific templating config applied.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Joining consecutive lines with <code>paste</code></title>
    <link href="https://notes.aflukasz.pl/en/2025/07/14/joining-lines-paste"/>
    <id>https://notes.aflukasz.pl/en/2025/07/14/joining-lines-paste</id>
    <published>2025-07-14T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/07/14/joining-lines-paste">
&lt;h1&gt;Short intro to &lt;code&gt;paste&lt;/code&gt;&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;paste&lt;/code&gt; is a tool &lt;a href=&#34;https://pubs.opengroup.org/onlinepubs/9799919799/utilities/paste.html&#34;&gt;defined in POSIX &lt;/a&gt;
as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The paste utility shall concatenate the corresponding lines of the given input files, and write the resulting lines to standard output.&lt;/p&gt;
&lt;p&gt;The default operation of paste shall concatenate the corresponding lines of the input files. The &amp;lt;newline&amp;gt; of every line except the line from the last input file shall be replaced with a &amp;lt;tab&amp;gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And &lt;code&gt;man&lt;/code&gt; from GNU core utilities explains:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SYNOPSIS&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  paste [OPTION]... [FILE]...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;DESCRIPTION&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  Write lines consisting of the sequentially corresponding lines from each FILE, separated by TABs, to standard output.
&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&#39;s see an example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ cat a.txt
1
2
3

$ cat b.txt
101
102
103

$ paste a.txt b.txt
1       101
2       102
3       103
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ok, from the above we see that this can be quite useful. &lt;strong&gt;But wait, there is
one behavior that can be missed at a first glance...&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;Passing stdin&lt;/h1&gt;
&lt;p&gt;&lt;code&gt;paste&lt;/code&gt; can take &lt;code&gt;-&lt;/code&gt; (a dash) as a source parameter to
read from stdin. So far nothing special, but what is worth noting is that if we
pass stdin parameter multiple times, we will keep reading from the same file
descriptor in all the instances, each time incrementing same shared read
offset over same input.&lt;/p&gt;
&lt;p&gt;This is a special case behavior for stdin as &lt;code&gt;paste&lt;/code&gt; parameter (vs passing
file paths to same files). And a quite natural one, given that there is one
stdin to a program.&lt;/p&gt;
&lt;p&gt;While I don&#39;t see this being explicitely documented in the manual for
coreutils implementation, this property is mentioned in POSIX:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If &#39;-&#39; is specified for one or more of the files, the standard input shall be used; the standard input shall be read one line at a time, circularly, for each instance of &#39;-&#39;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;In principle&lt;/em&gt; a program could implement stdin buffering to allow
for multiple independent reads of stdin contents, but that&#39;s not what we are dealing
with here, including the coreutils implementation.&lt;/p&gt;
&lt;h1&gt;Joining consecutive lines from a single source&lt;/h1&gt;
&lt;p&gt;Now that we see that state (read offset) is shared for all the occurrences of
stdin passed to &lt;code&gt;paste&lt;/code&gt;, we can observe that this allows, for example, for
merging consecutive lines from a single file, like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ cat a.txt
1
2
3

$ cat a.txt | paste - -
1       2
3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example text is read via stdin, but &lt;strong&gt;because stdin is declared as
input &lt;em&gt;twice&lt;/em&gt;, process of assembling each output line reads two &lt;em&gt;consecutive&lt;/em&gt; lines
from the single input&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is as opposed to each of the two instances of stdin parameter generating
own instance of a read offset, resulting in reading each line twice.&lt;/p&gt;
&lt;p&gt;To further illustrate the difference, we can get back to having
such effect of independent read offsets per (same) file parameter, if we point
twice to the same file using file paths instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ paste a.txt a.txt
1       1
2       2
3       3
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above there are two independent read offsets at play, one per file (per opened
file descriptor) - which just happens to be the same file.&lt;/p&gt;
&lt;h1&gt;Less synthetic example&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;/en/2025/05/09/pbkdf2-iterations-count-django&#34;&gt;I&#39;ve used this property recently&lt;/a&gt;
when operating on the output of &lt;code&gt;git log -p&lt;/code&gt; which was showing, among others,
dates of commits and commit patches. What I wanted was to get (date, specific
line diff) pairs in one line. &lt;code&gt;paste&lt;/code&gt; and this usage of stdin allowed me to get
from a form like...&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;date 1
diff line 1
date 2
diff line 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... to this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;date 1 diff line 1
date 2 diff line 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;by simply adding &lt;code&gt;| paste - -&lt;/code&gt; to the pipeline.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>PostgreSQL does not store time zone in `timestamp with time zone` data type</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/30/postgresql-timestamp-storage"/>
    <id>https://notes.aflukasz.pl/en/2025/05/30/postgresql-timestamp-storage</id>
    <published>2025-05-30T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/30/postgresql-timestamp-storage">

&lt;p&gt;PostgreSQL has two variants of a type called &#34;timestamp&#34;: &lt;code&gt;timestamp with time zone&lt;/code&gt; and &lt;code&gt;timestamp without time zone&lt;/code&gt;. At a first glance, it looks as if those two data types must differ in terms of what and how is being stored, but that&#39;s not exactly the case.&lt;/p&gt;
&lt;p&gt;In PostgreSQL, &lt;strong&gt;&lt;code&gt;with time zone&lt;/code&gt; variant doesn&#39;t physically store any time zone information.&lt;/strong&gt; This fact is a key to understand how those two types do differ and what are their use cases. But that&#39;s for another story - here we focus on storage format aspect.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.postgresql.org/docs/17/datatype-datetime.html&#34;&gt;Documentation on Date/Time types&lt;/a&gt; has this to say about what we discuss here: both types have storge size of 8 bytes and for &lt;code&gt;timestamp with time zone&lt;/code&gt; &#34;the value is stored internally as UTC, and the originally stated or assumed time zone is not retained.&#34;&lt;/p&gt;
&lt;p&gt;As this fact of not storing time zone anywhere is somewhat burried within the docs and is quite confusing, it&#39;s worth taking a look at how this is actually true. In fact, we will see not only how time zone information is lost at &lt;code&gt;INSERT&lt;/code&gt; time, but also that &lt;strong&gt;instances of both variants of &lt;code&gt;timestamp&lt;/code&gt; have exactly same physical representation inside the data page.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;First, we will load a single row containing one &lt;code&gt;without time zone&lt;/code&gt; and one &lt;code&gt;with time zone&lt;/code&gt; timestamp value:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ psql &amp;lt;&amp;lt;EOF
-- Create table
drop table if exists test;
create table test (
    tnotz   timestamp without time zone,
    ttz     timestamp with time zone
);

-- Insert actual data
insert into test (tnotz, ttz) values (
    &#39;2000-01-01 01:00:00&#39;,
    &#39;2000-01-01 01:00:00&#39; at time zone &#39;utc&#39;
);

-- Flush WAL so that table data file is up to date
checkpoint;
EOF
DROP TABLE
CREATE TABLE
INSERT 0 1
CHECKPOINT
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And now let&#39;s take a peek inside the table data file:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ psql -tAc &#34;select version()&#34;
PostgreSQL 17.4 on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit

$ hexdump -C &#34;$PGDATA/$(psql -tAc &#34;SELECT pg_relation_filepath(&#39;test&#39;)&#34;)&#34;
00000000  00 00 00 00 68 af b6 01  83 1d 00 00 1c 00 d8 1f  |....h...........|
00000010  00 20 04 20 00 00 00 00  d8 9f 50 00 00 00 00 00  |. . ......P.....|
00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00001fd0  00 00 00 00 00 00 00 00  e8 02 00 00 00 00 00 00  |................|
00001fe0  00 00 00 00 00 00 00 00  01 00 02 00 00 08 18 00  |................|
00001ff0  00 a4 93 d6 00 00 00 00  00 a4 93 d6 00 00 00 00  |................|
00002000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First three rows above are the &lt;a href=&#34;https://www.postgresql.org/docs/17/storage-page-layout.html#STORAGE-PAGE-LAYOUT-FIGURE&#34;&gt;page header&lt;/a&gt; plus some of the subsequent empty space. After that we encounter our only table row. It starts with its own header and then we can see our two columns, both
having &lt;em&gt;exactly&lt;/em&gt; same physical representation on 8 bytes: &lt;code&gt;00 a4 93 d6 00 00 00 00&lt;/code&gt;. Both instances of this sequence are present, one after the other, on the last line of &lt;code&gt;hexdump&lt;/code&gt; output.&lt;/p&gt;
&lt;p&gt;Those 8 bytes represent the number of microseconds &lt;a href=&#34;https://github.com/postgres/postgres/blob/REL_17_STABLE/src/backend/utils/adt/timestamp.c#L607&#34;&gt;since&lt;/a&gt; &lt;a href=&#34;https://github.com/postgres/postgres/blob/REL_17_STABLE/src/include/datatype/timestamp.h#L235&#34;&gt;Jan 1st 2000&lt;/a&gt;. Both timestamps that we&#39;ve inserted earlier are pointing to exactly one hour past that moment, so what we see is simply the number of microseconds within one hour:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ python -c &#34;print(int.from_bytes(bytes.fromhex(&#39;00 a4 93 d6 00 00 00 00&#39;), &#39;little&#39;) == 1 * 60 * 60 * 1_000_000)&#34;
True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, both timestamps are stored in the same way - as the same epoch value. And the time zone is nowhere to be seen. &lt;strong&gt;The difference between those two data types lies in the read and write semantics&lt;/strong&gt; - likely to be explored on some other occasion.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>No favicon</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/29/no-favicon"/>
    <id>https://notes.aflukasz.pl/en/2025/05/29/no-favicon</id>
    <published>2025-05-29T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/29/no-favicon">

&lt;p&gt;Web browsers really like favicons. If your site does not declare one with
&lt;code&gt;&amp;lt;link rel=&#34;icon&#34;&amp;gt;&lt;/code&gt;, most (all?) of the mainstream ones will issue request to
&lt;code&gt;/favicon.ico&lt;/code&gt; anyway, in a hope of getting one.&lt;/p&gt;
&lt;p&gt;Favicons are a whole topic on its own.  But what if we don&#39;t use one? Can we
somehow nudge browsers towards actually not looking for it? For saving them
from making an extra request and for making dev tools and server logs less
noisy from all those 404s.&lt;/p&gt;
&lt;p&gt;Yes. &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/URI/Reference/Schemes/data&#34;&gt;Data urls&lt;/a&gt; to the rescue. They allow us to inline contents directly within the page source. &lt;a href=&#34;https://caniuse.com/datauri&#34;&gt;Caniuse reports 97% coverage&lt;/a&gt; and MDN marks them in their &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility&#34;&gt;baseline classification&lt;/a&gt; as &#34;Widely available&#34;.&lt;/p&gt;
&lt;p&gt;The syntax is &lt;code&gt;data:[&amp;lt;media-type&amp;gt;][;base64],&amp;lt;data&amp;gt;&lt;/code&gt;. Here we use data url to inline an empty string:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-html&#34;&gt;&amp;lt;link rel=&#34;icon&#34; href=&#34;data:,&#34; /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In principle this should make supporting browsers to behave as if we served an empty
file from remote host. From my short experiments I can see this works fine (meaning:
no favicons request) with Firefox, Chromium and Chrome. On mobile Safari
I&#39;ve caught single requests here and there despite the above &lt;code&gt;link&lt;/code&gt;, so not sure.&lt;/p&gt;
&lt;p&gt;Any potential issues coming from the above approach (like browser fetching remote file
despite data url) may be related not to the data scheme usage itself, but to the
embedding of an empty string. Inlining an actual small &#34;empty&#34; image could
maybe improve the effect in some cases. Although, arguably, this starts being
close to... just having an actual favicon.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Hiding /etc/shadow from Debian psql wrapper</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/28/psql-shadow-debian"/>
    <id>https://notes.aflukasz.pl/en/2025/05/28/psql-shadow-debian</id>
    <published>2025-05-28T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/28/psql-shadow-debian">

&lt;p&gt;In the recent note titled &lt;a href=&#34;/en/2025/05/23/psql-shadow-bwrap&#34;&gt;&#34;Hiding /etc/shadow from psql&#34;&lt;/a&gt;, I&#39;ve
mentioned how calling &lt;code&gt;psql&lt;/code&gt; was causing &lt;code&gt;auditd&lt;/code&gt; to log denied reads of
&lt;code&gt;/etc/shadow&lt;/code&gt; and have showed one way to deal with this. Here is the continuation of this story, as thanks to insights from &lt;a href=&#34;https://bsky.app/profile/hillu.bsky.social&#34;&gt;@hillu.bsky.social&lt;/a&gt;, it&#39;s clear that I&#39;ve missed an important detail.&lt;/p&gt;
&lt;p&gt;On Debian &lt;code&gt;/usr/bin/psql&lt;/code&gt; is actually a distro specific wrapper over
the actual &lt;code&gt;psql&lt;/code&gt; binary. I missed that previously:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ ls -l /usr/bin/psql
lrwxrwxrwx 1 root root 37 Mar 14  2023 /usr/bin/psql -&amp;gt; ../share/postgresql-common/pg_wrapper
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is part of Debian&#39;s mechanism for managing multiple PostgreSQL clusters
and versions. So the behavior I&#39;ve observed earlier is Debian specific.&lt;/p&gt;
&lt;p&gt;And as &lt;a href=&#34;https://bsky.app/profile/hillu.bsky.social/post/3lpzmk437rc22&#34;&gt;@hillu pointed out&lt;/a&gt;, &lt;code&gt;/etc/shadow&lt;/code&gt; read is ultimately triggered by &lt;code&gt;getpwuid&lt;/code&gt;
Perl builtin. Which is called by &lt;code&gt;/usr/share/perl5/PgCommon.pm&lt;/code&gt;, called from
&lt;code&gt;/usr/share/postgresql-common/pg_wrapper&lt;/code&gt; by invoking &lt;code&gt;user_cluster_map()&lt;/code&gt;. If I understood correctly, the
actual read of &lt;code&gt;/etc/shadow&lt;/code&gt; is not needed and is only a side effect of triggering
&lt;code&gt;getpwuid&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Anyway, the following line of the &lt;code&gt;postgresql-common/pg_wrapper&lt;/code&gt; suggests one way to avoid
this excessive read attempt:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-pl&#34;&gt;($version, $cluster, $db) = user_cluster_map() unless ($cluster or $explicit_host or $explicit_port);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Passing explicit connection info to &lt;code&gt;psql&lt;/code&gt; will stop the wrapper
from entering the code path that ends on shadow file read. But the form of such
call is not arbitrary - in &lt;a href=&#34;/en/2025/05/23/psql-shadow-bwrap&#34;&gt;the original scenario&lt;/a&gt;
connection params were in fact passed, but using &lt;code&gt;--dbname CONNSTRING&lt;/code&gt;. And Debian wrapper
is not trying to extract anything from that. But it does understand
&lt;code&gt;psql -h&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And even without resigning from using &lt;code&gt;--dbname CONNSTRING&lt;/code&gt; form, we can still
escape the issue by adding extra explicit &lt;code&gt;-h HOST&lt;/code&gt;. In fact, turns out &lt;code&gt;HOST&lt;/code&gt;
can be anything then, because as &lt;a href=&#34;https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-OPTION-DBNAME&#34;&gt;&lt;code&gt;psql&lt;/code&gt; docs state&lt;/a&gt;, &#34;--dbname [...] can be a connection string. If so, connection string parameters will override any conflicting command line options&#34;. At the same time our Perl wrapper
will be happy not to call &lt;code&gt;user_cluster_map&lt;/code&gt; and leave &lt;code&gt;/etc/shadow&lt;/code&gt; alone:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;psql --dbname CONNSTRING -h dummy
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But that&#39;s little hacky. Ideally, &lt;code&gt;PgCommon.pm&lt;/code&gt; would not be using &lt;code&gt;getpwuid&lt;/code&gt; at all.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Ansible and temporary dynamic hosts</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/27/ansible-temporary-dynamic-hosts"/>
    <id>https://notes.aflukasz.pl/en/2025/05/27/ansible-temporary-dynamic-hosts</id>
    <published>2025-05-27T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/27/ansible-temporary-dynamic-hosts">

&lt;p&gt;Ansible has a task called &lt;a href=&#34;https://docs.ansible.com/ansible/latest/collections/ansible/builtin/add_host_module.html&#34;&gt;&lt;code&gt;add_host&lt;/code&gt;&lt;/a&gt;. It adds extra hosts to the inventory at play execution time. It has two non obvious properties, though.&lt;/p&gt;
&lt;p&gt;First, such a host is not automatically selected as execution target during current play. Only subsequent plays, that run in the same execution context, can match such new host with host selectors. The other is that such added hosts will stay in the inventory to the end of
execution context.&lt;/p&gt;
&lt;p&gt;This second property can sometimes be particularly tricky, because you may be writing your play
and, at first, thinking about it in isolation. But later on you may want to
include it as part of a bigger playbook containing other plays.&lt;/p&gt;
&lt;p&gt;In such a situation, any subsequent plays, if they match this new host, e.g.
via &lt;code&gt;all&lt;/code&gt; selector, will execute on it.&lt;/p&gt;
&lt;p&gt;Now, this may be something that you want. Or maybe you have used &lt;code&gt;add_host&lt;/code&gt;
as a temporary target that does not make sense to be modified by other plays. In
this second scenario you have a problem.&lt;/p&gt;
&lt;p&gt;Before Ansible 2.14 it was possible to clear inventory from such added hosts
with &lt;code&gt;meta: refresh_inventory&lt;/code&gt;. I believe it was not documented, though. Then this behavior became &lt;a href=&#34;https://github.com/ansible/ansible/issues/59400&#34;&gt;classified as a bug&lt;/a&gt; (2019) and later ultimately &lt;a href=&#34;https://github.com/ansible/ansible/blob/stable-2.14/changelogs/CHANGELOG-v2.14.rst#id57&#34;&gt;fixed&lt;/a&gt; (2022), meaning it has stopped being
a way to drop temporary, playbook specific hosts from the inventory.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/ansible/proposals/issues/174&#34;&gt;This proposal&lt;/a&gt; on the other hand is
open and discusses option to add &lt;code&gt;remove_host&lt;/code&gt; task, that would be a proper
and explicit way of removing dynamic hosts from the inventory at run time. This would be a very useful addition.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Hiding /etc/shadow from psql</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/23/psql-shadow-bwrap"/>
    <id>https://notes.aflukasz.pl/en/2025/05/23/psql-shadow-bwrap</id>
    <published>2025-05-23T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/23/psql-shadow-bwrap">

&lt;p&gt;&lt;del&gt;&lt;code&gt;psql&lt;/code&gt;&lt;/del&gt; Debian wrapper of &lt;code&gt;psql&lt;/code&gt; (see &lt;a href=&#34;/en/2025/05/28/psql-shadow-debian&#34;&gt;this update&lt;/a&gt;), at least in version 15.12, really likes &lt;code&gt;/etc/shadow&lt;/code&gt; file. To such a
degree that it tries to read it upon each invocation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ strace psql 2&amp;gt;&amp;amp;1 | grep /etc/shadow
openat(AT_FDCWD, &#34;/etc/shadow&#34;, O_RDONLY|O_CLOEXEC) = -1 EACCES (Permission denied)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On this particular host, such event is logged by &lt;code&gt;auditd&lt;/code&gt; (output edited for brevity):&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;type=SYSCALL syscall=257 success=no exit=-13 comm=&#34;psql&#34; exe=&#34;/usr/bin/perl&#34; SYSCALL=openat
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see, this read attempt failed. Actually, that&#39;s the reason it got
logged. And it failed because this specific user calling &lt;code&gt;psql&lt;/code&gt;
does not have read access to &lt;code&gt;/etc/shadow&lt;/code&gt;. This is not some weird custom setup,
just standard Debian 12 system, where shadow is readable only by &lt;code&gt;root&lt;/code&gt; and the
&lt;code&gt;shadow&lt;/code&gt; group - it&#39;s a small club and we ain&#39;t in it.&lt;/p&gt;
&lt;p&gt;But, in a parallel incarnation, we are also &lt;code&gt;root&lt;/code&gt; here and thus recipients of
alerting from this system. And it just so happens that just as &lt;code&gt;psql&lt;/code&gt; likes to
read &lt;code&gt;/etc/shadow&lt;/code&gt;, &lt;code&gt;auditd&lt;/code&gt; is set such that it doesn&#39;t like &lt;code&gt;shadow&lt;/code&gt; being read by unworthy souls - and it
pages us if that happens. And it does happen frequently, because non-root users
on this host like to run &lt;code&gt;psql&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, how could we solve this conundrum? We could add appropriate users to the
&lt;code&gt;shadow&lt;/code&gt; group, sure. But let&#39;s say we deem this excessive. In this particular
case &lt;code&gt;bwrap&lt;/code&gt; became a cure of choice:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;bwrap \
    --ro-bind /usr /usr \
    --ro-bind /lib /lib \
    --ro-bind /lib64 /lib64 \
    --ro-bind /etc/hosts /etc/hosts \
    --bind /home /home \
    --proc /proc \
    --dev /dev \
psql
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This hides shadow file from &lt;code&gt;psql&lt;/code&gt; and eliminates the issue. Of course this
works only if we can otherwise ensure that all calls to &lt;code&gt;psql&lt;/code&gt; will go
via such wrapping script.&lt;/p&gt;
&lt;p&gt;Also note that &lt;code&gt;psql&lt;/code&gt; reads a few more files from &lt;code&gt;/etc&lt;/code&gt; than just &lt;code&gt;shadow&lt;/code&gt;, so this
specific invocation as above may be little too restrictive - e.g. we block
&lt;code&gt;/etc/nsswitch.conf&lt;/code&gt;. But in this particular setup it was good enough.&lt;/p&gt;
&lt;p&gt;Is there a simpler way?&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>PostgreSQL direct SSL</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/22/postgresql-ssl-direct"/>
    <id>https://notes.aflukasz.pl/en/2025/05/22/postgresql-ssl-direct</id>
    <published>2025-05-22T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/22/postgresql-ssl-direct">

&lt;p&gt;PostgreSQL in version 17 introduced &lt;a href=&#34;https://www.postgresql.org/docs/17/libpq-connect.html#LIBPQ-CONNECT-SSLNEGOTIATION&#34;&gt;&lt;code&gt;sslnegotiation&lt;/code&gt; connection param&lt;/a&gt;. Setting it to &lt;code&gt;direct&lt;/code&gt; skips asking the server if it supports SSL connections and proceeds establishing such connection directly.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://marc-bowes.com/postgres-direct-tls.html&#34;&gt;This post&lt;/a&gt; mentions using that to save seconds (!) in connection times, but in a very specific circumstances, where additional factors greatly amplified observed performance. The post itself is interesting on its own. It does not, however, mention how much could be saved with &lt;code&gt;direct&lt;/code&gt; mode in more general case.&lt;/p&gt;
&lt;p&gt;So let&#39;s do a quick and dirty experiment where &lt;code&gt;sslnegotiation&lt;/code&gt; performance impact will be more realistic. We run both client and server on the same host.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ multitime -n 1000 -s 0 psql --dbname &#34;postgresql://test:test@localhost?sslmode=verify-ca&amp;amp;sslrootcert=ca.crt&amp;amp;sslnegotiation=postgres&#34; -c &#34;\q&#34;
===&amp;gt; multitime results
1: psql --dbname postgresql://test:test@localhost?sslmode=verify-ca&amp;amp;sslrootcert=ca.crt&amp;amp;sslnegotiation=postgres -c \q
            Mean        Std.Dev.    Min         Median      Max
real        0.050       0.010       0.030       0.049       0.092
user        0.029       0.008       0.008       0.028       0.059
sys         0.007       0.004       0.000       0.007       0.023

$ multitime -n 1000 -s 0 psql --dbname &#34;postgresql://test:test@localhost?sslmode=verify-ca&amp;amp;sslrootcert=ca.crt&amp;amp;sslnegotiation=direct&#34; -c &#34;\q&#34;
===&amp;gt; multitime results
1: psql --dbname postgresql://test:test@localhost?sslmode=verify-ca&amp;amp;sslrootcert=ca.crt&amp;amp;sslnegotiation=direct -c \q
            Mean        Std.Dev.    Min         Median      Max
real        0.048       0.010       0.029       0.047       0.100
user        0.029       0.008       0.008       0.028       0.054
sys         0.007       0.004       0.000       0.007       0.027
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So a slight difference is visible - here it&#39;s on the order of fractions of milliseconds.&lt;/p&gt;
&lt;p&gt;Start of &lt;code&gt;psql&lt;/code&gt; itself was probably source of some noise. Also, we stayed on localhost, so had no network latency - connecting to remote host should make those results more in favor of &lt;code&gt;=direct&lt;/code&gt;.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Guessable web URLs?</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/21/guessable-urls"/>
    <id>https://notes.aflukasz.pl/en/2025/05/21/guessable-urls</id>
    <published>2025-05-21T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/21/guessable-urls">

&lt;p&gt;Recently I&#39;ve landed on a blog post from 2011 titled &lt;a href=&#34;https://alanhogan.com/url-as-ui&#34;&gt;&#34;URL as UI&#34;&lt;/a&gt;. One claim caught my eye in particular - &#34;an ideal URL is guessable&#34;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Synonyms should ideally redirect. If you have a support page at /support and a user types /help, is that really such a bad request? Don&#39;t show them a 404 — send them to the page they&#39;re looking for!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Yes, in principle that looks like a great idea. You show thoughtfulness, care,
you guide your user.&lt;/p&gt;
&lt;p&gt;Also, as we are in the area of text input UIs (after all, we are considering user
manually entering or changing URL of the web page - &#34;guessing it&#34;), it&#39;s only natural to note similarity of this idea to the existence of conventions in CLIs used in various userspace ecosystems.&lt;/p&gt;
&lt;p&gt;For example, in GNU tooling, it&#39;s almost a given that I can ask for &lt;code&gt;--help&lt;/code&gt;, for
being &lt;code&gt;--verbose&lt;/code&gt; or to get &lt;code&gt;--version&lt;/code&gt;, even without studying any manual first.&lt;/p&gt;
&lt;p&gt;But do users actually navigate the web like that?&lt;/p&gt;
&lt;p&gt;My intuition is that they (we) tweak URLs only if they (we) already see some
structure and for some reason it&#39;s easier to change it directly, than to use
actual page interface. Examples would be navigating paginated lists, tweaking
search results, changing names of user profiles shown, checking (for a friend)
if the backend verifies permissions correctly...&lt;/p&gt;
&lt;p&gt;But to just blindly navigate to /help or /about and expect to land somewhere?
Somehow I don&#39;t see it. Yes, some fringe internet dwellers may try /feed or /blog,
but if I were to guess, that&#39;s about it. Link to it or it didn&#39;t happen.&lt;/p&gt;
&lt;p&gt;There is simply no established behavioral pattern of such usage. I&#39;m willing
to bet that this relates not only to &#34;normies&#34;, but also to so called power
users.&lt;/p&gt;
&lt;p&gt;Yes, /help redirecting to /support makes sense, if /help existed before and doesn&#39;t
anymore. But that&#39;s a different case than guessable URLs.&lt;/p&gt;
&lt;p&gt;But hey, this is n=1. Maybe there is some grumpy greybeard Links/Lynx user, or some &lt;a href=&#34;https://www.nngroup.com/&#34;&gt;Nielsen Norman Group&lt;/a&gt; article willing to make me look silly?&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Fancy tail -F</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/20/fancy-tail-f"/>
    <id>https://notes.aflukasz.pl/en/2025/05/20/fancy-tail-f</id>
    <published>2025-05-20T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/20/fancy-tail-f">

&lt;p&gt;This is slightly embarrassing, but I&#39;ve learned just recently that &lt;code&gt;tail&lt;/code&gt; command has &lt;code&gt;-F&lt;/code&gt; option. It&#39;s a CAPITAL F, not commonly used lower case &lt;code&gt;-f&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It&#39;s not POSIX standardized, but many implementations have it. GNU coreutils is an example closest to my daily usage, but I can see that (apparently similar) implementations are present in e.g. FreeBSD, NetBSD or Busybox (here behind a compile time flag called IF_FEATURE_FANCY_TAIL).&lt;/p&gt;
&lt;p&gt;Given contents of related manuals, exact details of behavior may differ, but most, if not all, share this property as described by man from coreutils: &#34;keep trying to open a file if it is inaccessible&#34; (and otherwise behave as &lt;code&gt;-f&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;This is really convenient. For example when working with some process that we continue to start, stop, cleanup, and then start again. I don&#39;t know how many times this included me going back to a window with tail, just to restart it, to again track a new instance of some file written to.&lt;/p&gt;
&lt;p&gt;Another use case would be tracking rotated log file over a longer period of time.&lt;/p&gt;
&lt;p&gt;Anyway, I&#39;ve just become &lt;a href=&#34;https://xkcd.com/1053/&#34;&gt;lucky 10000&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Rigid file name schemes and interoperability</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/19/file-names-scheme-interop"/>
    <id>https://notes.aflukasz.pl/en/2025/05/19/file-names-scheme-interop</id>
    <published>2025-05-19T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/19/file-names-scheme-interop">

&lt;p&gt;Some programs require that the name of the passed file has a specific scheme. For example, just now I want to start &lt;code&gt;programX&lt;/code&gt; and it won&#39;t work, if config file has no proper extension.&lt;/p&gt;
&lt;p&gt;There are better or worse reasons to do that. But the cons include, at a minimum, reduced interoperability.&lt;/p&gt;
&lt;p&gt;For example, &#34;process substitution&#34; is a convenient way to pass file-like objects constructed on the fly from the output of an arbitrary command. In Bash, we should be able to run&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ programX --config &amp;lt;( cmd )
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;cmd&lt;/code&gt; generates config contents.&lt;/p&gt;
&lt;p&gt;But because we have no control over the name under which this file-like object is accessible, we can&#39;t force it to have extension in its name.&lt;/p&gt;
&lt;p&gt;Sure, we can always write even more shell to circumvent that. And sure, Zsh has &lt;code&gt;=()&lt;/code&gt; variant, which writes to an actual file which name we can control (or so I&#39;ve read).&lt;/p&gt;
&lt;p&gt;But that&#39;s the point. Interop suffered here.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>AWS Reachability Analyzer</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/15/aws-reachability-analyzer"/>
    <id>https://notes.aflukasz.pl/en/2025/05/15/aws-reachability-analyzer</id>
    <published>2025-05-15T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/15/aws-reachability-analyzer">

&lt;p&gt;Motivated by one of those &#34;why can&#39;t A access B on AWS&#34; questions I just saw, a short reminder - AWS has this thing called... Reachability Analyzer.&lt;/p&gt;
&lt;p&gt;The name is straight to the point, and such is the tool itself. It allows you to create a set of named paths between points in your infrastructure, and test if they can be traversed end to end or not.&lt;/p&gt;
&lt;p&gt;Apart from yes/no answer, you also get a nice visualization of how that path was laid out across systems. For example, I&#39;m looking at one right now and can see following &#34;route&#34; that works:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ec2 -&amp;gt; eni -&amp;gt; sg -&amp;gt; acl -&amp;gt; rtb -&amp;gt; acl -&amp;gt; sg -&amp;gt; eni -&amp;gt; rds
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the other hand, example of encountering an issue may look like that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SUBNET_ACL_RESTRICTION:&lt;/p&gt;
&lt;p&gt;Network ACL acl-abcdef01 does not allow inbound traffic from subnet-abcdef02 to vpc-abcdef03.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Tests for each path can be rerun, to see if anything changed across time.&lt;/p&gt;
&lt;p&gt;It&#39;s not something I&#39;ve used very frequently, but boy was I glad it existed those few times in the past.&lt;/p&gt;
&lt;p&gt;GCP and Azure seem to have similar tools.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Pushing a single flexbox item to the flexbox-end and wrapping</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/14/flexbox-pushing-single-item"/>
    <id>https://notes.aflukasz.pl/en/2025/05/14/flexbox-pushing-single-item</id>
    <published>2025-05-14T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/14/flexbox-pushing-single-item">

&lt;p&gt;When using CSS flexbox, I have this tendency to use &lt;code&gt;margin: auto&lt;/code&gt; whenever I want to push single item to the flex-end.&lt;/p&gt;
&lt;p&gt;For example (assuming ltr mode here and for the rest of this note), inside &lt;code&gt;display:flex; flex-direction: column&lt;/code&gt; I would put &lt;code&gt;margin-left: auto&lt;/code&gt; on the last item, to make it stick to the right edge, while keeping rest of them to the left.&lt;/p&gt;
&lt;p&gt;Fine, you can do that, but it&#39;s probably not what you want, if you also need to &lt;code&gt;flex-wrap: wrap&lt;/code&gt; your container. Because then, if your row does wrap, you will get second row, with single item, pushed to the right edge, leaving all this whitespace on the left of the otherwise empty row.&lt;/p&gt;
&lt;p&gt;I mean, you &lt;em&gt;could&lt;/em&gt; want it, but in, say, typical example of navigation menu, where - as the view port becomes smaller - you want to transition from a single row towards vertically stacked items, that is rather not a desired effect. What looked good on a single row, now makes not much sense.&lt;/p&gt;
&lt;p&gt;For now my cure of choice for such situations is &lt;code&gt;justify-content: space-between&lt;/code&gt; on container. For a single row it works as &lt;code&gt;margin-left: auto&lt;/code&gt; while not breaking on wrap.&lt;/p&gt;
&lt;p&gt;Alas this works only when we have exactly two items. Which can be enforced by additional wrapping of two groups: one with n-1 items and one with single n-th item.&lt;/p&gt;
&lt;p&gt;But I feel and hope that there is a better way somehow.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>nftables syntax peculiarities</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/13/nftables-syntax-peculiarities"/>
    <id>https://notes.aflukasz.pl/en/2025/05/13/nftables-syntax-peculiarities</id>
    <published>2025-05-13T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/13/nftables-syntax-peculiarities">

&lt;p&gt;nftables has some peculiarities in its syntax.&lt;/p&gt;
&lt;p&gt;One of my &#34;favorites&#34; is the fact that you can&#39;t define an empty set while using &lt;code&gt;elements&lt;/code&gt; keyword and contents literal. For example, let&#39;s create a table:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nft add table test_tbl
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can add a set:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nft add set test_tbl test_set { type inet_service\; }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This set is empty - that works just fine. We could also initialize it with some values from the get go:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nft add set test_tbl test_set { type inet_service\; elements = {80}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But what is not possible (nftables v1.0.6) is using contents literal while keeping the set empty:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nft add set test_tbl test_set { type inet_service\; elements = {}}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above will result in:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;Error: syntax error, unexpected &#39;}&#39;
add set test_tbl test_set { type inet_service; elements = {} }
                                                           ^
Error: syntax error, unexpected end of file
add set test_tbl test_set { type inet_service; elements = {} }
^
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that is non intuitive and also unfortunate in the context of templating nftables config files - when filling &lt;code&gt;elements&lt;/code&gt; from a variable - because empty iterable case must be dealt with separately.&lt;/p&gt;
&lt;p&gt;Sometimes it&#39;s a matter of simple &lt;code&gt;if&lt;/code&gt;, but depending on the language, and if we already hold reference to the final values or maybe we need to create those on the fly, this can become a nuisance.&lt;/p&gt;
&lt;p&gt;Also, let&#39;s not forget all those looming bugs, just waiting for the edge case of the empty set.&lt;/p&gt;
&lt;p&gt;Anyway, there is probably some good reason for this.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>pgBackRest with backup uploads to S3 behind HTTP proxy</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/12/pgbackrest-http-proxy"/>
    <id>https://notes.aflukasz.pl/en/2025/05/12/pgbackrest-http-proxy</id>
    <published>2025-05-12T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/12/pgbackrest-http-proxy">

&lt;p&gt;&lt;a href=&#34;https://pgbackrest.org/&#34;&gt;pgBackRest&lt;/a&gt; does not support HTTP proxies (in its S3 client). This was raised on Github couple of times (&lt;a href=&#34;https://github.com/pgbackrest/pgbackrest/issues/879&#34;&gt;[1]&lt;/a&gt;, &lt;a href=&#34;https://github.com/pgbackrest/pgbackrest/issues/1085&#34;&gt;[2]&lt;/a&gt;, &lt;a href=&#34;https://github.com/pgbackrest/pgbackrest/issues/1639&#34;&gt;[3]&lt;/a&gt;, &lt;a href=&#34;https://github.com/pgbackrest/pgbackrest/issues/2164&#34;&gt;[4]&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Suggested workaround is to use &lt;a href=&#34;https://proxychains.sourceforge.net/&#34;&gt;ProxyChains&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Discovering you need to slap some extra component into a critical path of a critical workflow is exciting... Exciting as in need-to-go-to-a-dentist kind of exciting.&lt;/p&gt;
&lt;p&gt;But happy to confirm that it just works! With &lt;a href=&#34;https://www.squid-cache.org/&#34;&gt;Squid&lt;/a&gt; on the other end.&lt;/p&gt;
&lt;p&gt;End of story - for now.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Monitoring for data corruption in PostgreSQL</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/09/monitoring-data-corruption-postgresql"/>
    <id>https://notes.aflukasz.pl/en/2025/05/09/monitoring-data-corruption-postgresql</id>
    <published>2025-05-09T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/09/monitoring-data-corruption-postgresql">

&lt;p&gt;&lt;a href=&#34;https://postgres.fm/episodes/top-ten-dangerous-issues&#34;&gt;Latest episode of Postges FM podcast&lt;/a&gt; does interesting overview of top things to be aware of when operating PostgreSQL deployments.&lt;/p&gt;
&lt;p&gt;All are important, obviously, but if I were to chose one, corruption case is the worst.&lt;/p&gt;
&lt;p&gt;Let&#39;s say we have page checksums on, do regular backups and run test restoration as mandatory step for each of them:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;run full am check,&lt;/li&gt;
&lt;li&gt;run pg_checksums,&lt;/li&gt;
&lt;li&gt;read whole db via pg_dumpall &amp;gt; /dev/null,&lt;/li&gt;
&lt;li&gt;run reindex schema,&lt;/li&gt;
&lt;li&gt;run some application layer checks (e.g delta of number of records +- same as on prod),&lt;/li&gt;
&lt;li&gt;run app test environments on such restored databases (not always possible due to protecting client data).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On top of that, we alert on logs for &lt;a href=&#34;https://www.postgresql.org/docs/current/errcodes-appendix.html&#34;&gt;XX001 and XX002&lt;/a&gt;, among others of course.&lt;/p&gt;
&lt;p&gt;Can we still do better? Maybe run pg_dumpall&amp;gt;/dev/null on production periodically, if load allows?&lt;/p&gt;
&lt;p&gt;Also: Real fun doesn&#39;t start until you actually DO detect something is wrong...&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>PBKDF2 default iterations count history in Django</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/09/pbkdf2-iterations-count-django"/>
    <id>https://notes.aflukasz.pl/en/2025/05/09/pbkdf2-iterations-count-django</id>
    <published>2025-05-09T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/09/pbkdf2-iterations-count-django">

&lt;p&gt;History of the default PBKDF2 iterations count in Django hasher module used for hashing user passwords:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2013-09-19 12000
2014-07-11 20000
2015-01-16 24000
2015-09-19 30000
2016-05-20 36000
2017-01-17 100000
2018-05-13 120000
2018-05-17 150000
2018-12-27 180000
2019-09-12 216000
2020-05-04 260000
2021-01-14 320000
2021-09-16 390000
2022-05-10 480000
2023-01-13 580000
2023-02-04 720000
2023-09-15 870000
2024-05-03 1_000_000
2024-12-13 1_200_000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can get this exact output using fancy shell-Excel formula:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;git log --date short -p --grep pbkdf2 -i django/contrib/auth/hashers.py \
| grep -E &#34;Date:|\+.*iterations = [0-9]&#34; \
| sed -E s/&#34;^Date:\s+&#34;//g \
| grep iterations -B 1 \
| sed s/&#34;+ *iterations =&#34;/&#34;&#34;/g \
| grep -v &#34;\-\-&#34; \
| paste - - \
| sed -E s/&#34;\s+&#34;/&#34; &#34;/g \
| sort
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href=&#34;/en/2025/07/14/joining-lines-paste&#34;&gt;&lt;code&gt;paste&lt;/code&gt;&lt;/a&gt; saved my life here)&lt;/p&gt;
&lt;p&gt;Apparently current Django policy is to increase this value by around 20% per release: &lt;a href=&#34;https://docs.djangoproject.com/en/dev/internals/howto-release-django/#a-few-days-before-a-feature-freeze&#34;&gt;https://docs.djangoproject.com/en/dev/internals/howto-release-django/#a-few-days-before-a-feature-freeze&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By the way, for comparison, current OWASP recommendation seems to be standing at &#34;600k or more&#34; or, better yet, use Argon or scrypt, if you can: &lt;a href=&#34;https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html&#34;&gt;https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Don't confuse &lt;b&gt; element with &lt;strong&gt;, &lt;em&gt; or &lt;mark&gt;</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/08/mdn-semantics-of-b"/>
    <id>https://notes.aflukasz.pl/en/2025/05/08/mdn-semantics-of-b</id>
    <published>2025-05-08T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/08/mdn-semantics-of-b">

&lt;p&gt;&#34;Do not confuse the &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt; element with the &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt;, or &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; elements&#34;, says MDN page on &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt;: &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/b&#34;&gt;https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/b&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;But why, exactly? What kinds of daemons will we summon otherwise?&lt;/p&gt;
&lt;p&gt;Well, don&#39;t do it because &#34;the &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; element represents text of certain importance, &lt;code&gt;&amp;lt;em&amp;gt;&lt;/code&gt; puts some emphasis on the text and the &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; element represents text of certain relevance. The &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt; element doesn&#39;t convey such special semantic information [...]&#34;&lt;/p&gt;
&lt;p&gt;Ah, ok, I see... Now that&#39;s some serious semantic web thing going on - you can nearly feel it in your bones!&lt;/p&gt;
&lt;p&gt;But, in all the seriousness - it seems manageable and (relatively) clear, when you invest a few moments into reading some adjacent hypertext on MDN.&lt;/p&gt;
&lt;p&gt;We should be fine - daemons begone!&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>PostgreSQL 18 favourites</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/07/postgresql-18-favorites"/>
    <id>https://notes.aflukasz.pl/en/2025/05/07/postgresql-18-favorites</id>
    <published>2025-05-07T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/07/postgresql-18-favorites">

&lt;p&gt;&lt;a href=&#34;https://bsky.app/profile/winand.at/post/3loknwtyt322k&#34;&gt;@winand.at noted on Bluesky&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;New PostgreSQL tag: REL_18_BETA1&lt;/p&gt;
&lt;p&gt;So many features to check out…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My personal favorites are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;generated columns - trading compute for space, defined in single place and once,&lt;/li&gt;
&lt;li&gt;uuidv7() - time-sortable UUIDs,&lt;/li&gt;
&lt;li&gt;idle_replication_slot_timeout - automatic cleanup of unused replication slots,&lt;/li&gt;
&lt;li&gt;gin_index_check() - more consistency checks, e.g when test-restoring backups.&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>

  
  <entry>
    <title>gpg agent and run-time hidden config?</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/06/gpg-agent-runtime-config"/>
    <id>https://notes.aflukasz.pl/en/2025/05/06/gpg-agent-runtime-config</id>
    <published>2025-05-06T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/06/gpg-agent-runtime-config">

&lt;p&gt;Apparently no way to get config of currently running instance of gpg-agent?&lt;/p&gt;
&lt;p&gt;There is &lt;code&gt;gpgconf --list-options gpg-agent&lt;/code&gt;, but it only operates on what gpg-agent (would have) read from config file and does not take into account params passed to the agent cli.&lt;/p&gt;
&lt;p&gt;At least in gpg 2.2.40.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Upcloud free credits</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/05/upcloud-free-credits"/>
    <id>https://notes.aflukasz.pl/en/2025/05/05/upcloud-free-credits</id>
    <published>2025-05-05T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/05/upcloud-free-credits">

&lt;p&gt;UpCloud &lt;a href=&#34;https://upcloud.com/become-european-champion&#34;&gt;offers €5000 for European Businesses&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You need VAT-ID and have three months to use these up. But still, could be useful.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Quick look at Scaleway pricing</title>
    <link href="https://notes.aflukasz.pl/en/2025/05/03/scaleway-pricing"/>
    <id>https://notes.aflukasz.pl/en/2025/05/03/scaleway-pricing</id>
    <published>2025-05-03T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/05/03/scaleway-pricing">

&lt;p&gt;Funny how most of the cost of the smallest VM on &lt;a href=&#34;https://scaleway.com&#34;&gt;scaleway.com&lt;/a&gt; (1 shared vCPU, 1GB RAM) is actually... IPv4 address.&lt;/p&gt;
&lt;p&gt;Yes, you can drop it, in which case cost calculator estimates monthly bill of... 0.97€ + VAT (so for me that would be 1.19€).&lt;/p&gt;
&lt;p&gt;There are caveats, though: &#34;Limited availability and no SLA&#34; disclaimer, presence only in two out of nine availability zones, only 10GB of storage (with option to upgrade), storage only via network attached device (no local disk), 200Mbps bandwidth...&lt;/p&gt;
&lt;p&gt;And while this is understandable given the price, it&#39;s also that this instance type is not representative for the rest of the offering — Scaleway is not THAT cheap in general, when taking a look at pricing of bigger instances (per CPU/RAM). Still cheaper than AWS, though (vs its on demand tier). And has a cute web UI.&lt;/p&gt;</content>
  </entry>

  
  <entry>
    <title>Ansible casting None to bool</title>
    <link href="https://notes.aflukasz.pl/en/2025/04/29/ansible-casting-none-to-bool"/>
    <id>https://notes.aflukasz.pl/en/2025/04/29/ansible-casting-none-to-bool</id>
    <published>2025-04-29T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2025/04/29/ansible-casting-none-to-bool">

&lt;p&gt;Who would have though that Ansible behvior when casting null to bool will be
closer to SQL than to Python:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-shell&#34;&gt;$ python -c &#34;print(bool(None))&#34;
False

$ psql -tA -c &#34;select null::bool is null&#34;
t

$ ansible -o -m raw -a &#34;echo -n {{ None | bool | type_debug }}&#34; localhost
localhost | CHANGED | rc=0 | (stdout) NoneType
&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>

  
  <entry>
    <title>Data ordering in pg_dump output</title>
    <link href="https://notes.aflukasz.pl/en/2010/08/10/pg-dump-order"/>
    <id>https://notes.aflukasz.pl/en/2010/08/10/pg-dump-order</id>
    <published>2010-08-10T00:00:00+00:00</published>
    <content type="html" xml:base="https://notes.aflukasz.pl/en/2010/08/10/pg-dump-order">

&lt;h1&gt;Question&lt;/h1&gt;
&lt;p&gt;&lt;a href=&#34;https://stackoverflow.com/users/123891/littlek&#34;&gt;littlek&lt;/a&gt; notes on Stackoverflow:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I am finding that pg_dump will not always dump the database in the same way. It will dump things in a different order every time. Therefore, when I do a diff on the two database dumps, the comparison will result in the two files being different, when they are actually the same, just in a different order.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;And then they &lt;a href=&#34;https://stackoverflow.com/questions/2178907/postgres-pg-dump-dumps-database-in-a-different-order-every-time&#34;&gt;ask&lt;/a&gt;: Is there a different way I can go about doing the pg_dump?&lt;/p&gt;
&lt;h1&gt;My answer&lt;/h1&gt;
&lt;p&gt;As of May 2010 &lt;a href=&#34;http://archives.postgresql.org/pgsql-hackers/2010-04/msg00710.php&#34;&gt;a patch to pg_dump&lt;/a&gt; exists that may be helpful to all interested in this matter - it adds &lt;code&gt;--ordered&lt;/code&gt; option to this utility:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Using --ordered will order the data by primary key or unique index, if one exists, and use the &#34;smallest&#34; ordering (i.e. least number of columns required for a unique order).&lt;/p&gt;
&lt;p&gt;Note that --ordered could crush your database server if you try to order very large tables, so use judiciously.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I didn&#39;t test it, but I guess it&#39;s worth a try.&lt;/p&gt;</content>
  </entry>

  


</feed>