Feuerfest

Just the private blog of a Linux sysadmin

How to install DiagnosisTools on my Synology DiskStation 411, or: Why I love the Internet

Synology Inc. https://www.synology.com/img/products/detail/DS423/heading.png

I own a Synology DiskStation 411 - in short: DS411. It looks like the one in the picture - which shows the successor model DS423. The DS411 runs some custom Linux and therefore is missing a lot of common tools. Recently I had some network error which made my NAS unreachable from one of my Proxmox VMs. The debugging process was made harder as I had no tools such as lsof, strace or strings.

I googled a bit and learned that Synology offers a DiagnosisTool package which contains all these tools and more. The package center however showed no such package for me. From the search results I got that it should be shown in the package center if there is a compatible version for the DSM version running on the NAS. So seems there is no compatible version for my DS411 running DSM 6.4.2?

Luckily there is a command to install the tools: synogear install

root@DiskStation:~# synogear install
failed to get DiagnosisTool ... can't parse actual package download link from info file

Okay, that's uncool. But still doesn't explain why we can't install them. What does synogear install actually do? Time to investigate. As we have no stat or whereis we have to resort to command -v which is included in the POSIX standard. (Yes, which is available, but as command is available everywhere that's the better choice.)

root@DiskStation:~# command -v synogear
/usr/syno/bin/synogear
root@DiskStation:~# head /usr/syno/bin/synogear
#!/bin/sh

DEBUG_MODE="no"
TOOL_PATH="/var/packages/DiagnosisTool/target/tool/"
TEMP_PROFILE_DIR="/var/packages/DiagnosisTool/etc/"

STATUS_NOT_INSTALLED=101
STATUS_NOT_LOADED=102
STATUS_LOADED=103
STATUS_REMOVED=104

Nice! /usr/syno/bin/synogear is a simple shellscript. Therefore we can just run it in debug mode and see what is happening without having to read every single line.

root@DiskStation:~# bash -x synogear install
+ DEBUG_MODE=no
+ TOOL_PATH=/var/packages/DiagnosisTool/target/tool/
+ TEMP_PROFILE_DIR=/var/packages/DiagnosisTool/etc/
+ STATUS_NOT_INSTALLED=101
[...]
++ curl -s -L 'https://pkgupdate.synology.com/firmware/v1/get?language=enu&timezone=Amsterdam&unique=synology_88f6282_411&major=6&minor=2&build=25556&package_update_channel=stable&package=DiagnosisTool'
+ reference_json='{"package":{}}'
++ echo '{"package":{}}'
++ jq -e -r '.["package"]["link"]'
+ download_url=null
+ echo 'failed to get DiagnosisTool ... can'\''t parse actual package download link from info file'
failed to get DiagnosisTool ... can't parse actual package download link from info file
+ return 255
+ return 255
+ status=255
+ '[' 255 '!=' 102 ']'
+ return 1
root@DiskStation:~#

The main problem seems to be an empty JSON-Response from https://pkgupdate.synology.com/firmware/v1/get?language=enu&timezone=Amsterdam&unique=synology_88f6282_411&major=6&minor=2&build=25556&package_update_channel=stable&package=DiagnosisTool and opening that URL in a browser confirms it. So there really seems to be no package for my Model and DSM version combination.

Through my search I also learned that there is a package archive at https://archive.synology.com/download/Package/DiagnosisTool/ which listed several versions of the DiagnosisTool. One package for each CPU architecture. But that also didn't give many clues as I wasn't familiar with many of the CPU architectures and nothing seems to match my CPU. No Feroceon or 88FR131 or the like.

root@DiskStation:~# cat /proc/cpuinfo
Processor       : Feroceon 88FR131 rev 1 (v5l)
BogoMIPS        : 1589.24
Features        : swp half thumb fastmult edsp
CPU implementer : 0x56
CPU architecture: 5TE
CPU variant     : 0x2
CPU part        : 0x131
CPU revision    : 1

Hardware        : Synology 6282 board
Revision        : 0000
Serial          : 0000000000000000

As I didn't want to randomly install all sorts of packages for different CPU architectures - not knowing how good or bad Synology is in preventing the installation of non-matching packages, I opted for the r/synology subreddit and stopped my side-quest at this point, focusing on the main problem.

Random redditors to the rescue!

Nothing much happened for 2 months and I had already forgotten about that thread. My problem with the VM was solved in the meantime and I had no reason to pursue it any further.

Then someone replied. This person apparently did try all sorts of packages for the DiskStation additionally providing a link to the package that worked. It was there that I noticed something. The link provided was: https://global.synologydownload.com/download/Package/spk/DiagnosisTool/1.1-0112/DiagnosisTool-88f628x-1.1-0112.spk and I recognized the string 88f628x but couldn't pin down where I had spotted it. Only then it dawned on me: 88f for the Feroceon 88FR131 and 628x for all Synology 628x boards. Could this really be it?

Armed with this information I quickly identified https://global.synologydownload.com/download/Package/spk/DiagnosisTool/3.0.1-3008/DiagnosisTool-88f628x-3.0.1-3008.spk to be the last version for my DS411 and installed it via the package center GUI (button "Manual installation" and then navigated to the downloaded .spk file on my computer).

Note: The .spk file seems to be a normal compressed tar file and can be opened with the usual tools. The file structure inside is roughly the same as with any RPM or DEB package. Making it easy to understand what happens during/after package installation.

The installation went fine, no errors reported and after that synogear install worked:

root@DiskStation:~# synogear install
Tools are installed and ready to use.
DiagnosisTool version: 3.0.1-3008

And I was finally able to use lsof!

root@DiskStation:~# lsof -v
lsof version information:
    revision: 4.89
    latest revision: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/
    latest FAQ: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/FAQ
    latest man page: ftp://lsof.itap.purdue.edu/pub/tools/unix/lsof/lsof_man
    constructed: Mon Jan 20 18:58:20 CST 2020
    compiler: /usr/local/arm-marvell-linux-gnueabi/bin/arm-marvell-linux-gnueabi-ccache-gcc
    compiler version: 4.6.4
    compiler flags: -DSYNOPLAT_F_ARMV5 -O2 -mcpu=marvell-f -include /usr/syno/include/platformconfig.h -DSYNO_ENVIRONMENT -DBUILD_ARCH=32 -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -g -DSDK_VER_MIN_REQUIRED=600 -pipe -fstack-protector --param=ssp-buffer-size=4 -Wformat -Wformat-security -D_FORTIFY_SOURCE=2 -O2 -Wno-unused-result -DNETLINK_SOCK_DIAG=4 -DLINUXV=26032 -DGLIBCV=215 -DHASIPv6 -DNEEDS_NETINET_TCPH -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE -DLSOF_ARCH="arm" -DLSOF_VSTR="2.6.32" -I/usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/usr/include -I/usr/local/arm-marvell-linux-gnueabi/arm-marvell-linux-gnueabi/libc/usr/include -O
    loader flags: -L./lib -llsof
    Anyone can list all files.
    /dev warnings are disabled.
    Kernel ID check is disabled.

The redditor was also so nice to let me know that I have to execute synogear install each time before I can use these tools. Huh? Why that? Shouldn't they be in my path?

Turns out: No, the directory /var/packages/DiagnosisTool/target/tool/ isn't included into our PATH environment variable.

root@DiskStation:~# echo $PATH
/sbin:/bin:/usr/sbin:/usr/bin:/usr/syno/sbin:/usr/syno/bin:/usr/local/sbin:/usr/local/bin

synogear install does that. It copies /etc/profile to /var/packages/DiagnosisTool/etc/.profile, while removing all lines starting with PATH or export PATH. Adding the path to the tools directory to the new PATH and exporting that and setting the new .profile file in the ENV environment variable.

Most likely this is just a precaution for novice users.

And to check if the tools are "loaded" they grep if /var/packages/DiagnosisTool/target/tool/ is included in $PATH.

So yeah, there is no technical reason preventing us from just adding /var/packages/DiagnosisTool/target/tool/ to $PATH and be done with that.

And this is why I love the internet. I thought I would've never figured that out if not for someone to post an reply and included the file which worked.

New learnings

Synology mailed me about critical security vulnerabilities present in DSM 6.2.4-25556 Update 7 which are fixed in 6.2.4-25556 Update 8 (read the Release Notes). However the update wasn't offered to me via the normal update dialog in the DSM, as it is a staged rollout. Therefore I opted to download a patch file from the Synology support site. This means I did not download the whole DSM package for a specific version but just from one version to another. And here I noticed that the architecture name is included in the patch filename. Nice.

If you visit https://www.synology.com/en-global/support/download/DS411?version=6.2 do not just click on Download, instead opt to choose your current DSM version and the target version you wish to update to. Then you are offered a patch file and identifier/name for the architecture your DiskStation uses is part of the filename.

This should be a reliable way to identify the architecture for all Synology models - in case it isn't clear through the CPU/board name, etc. as in my case.

List of included tools

Someone ask me for a list of all tools which are included in the DiagnosesTool package. Here you go:

admin@DiskStation:~$ ls -l /var/packages/DiagnosisTool/target/tool/ | awk '{print $9}'
addr2line
addr2name
ar
arping
as
autojump
capsh
c++filt
cifsiostat
clockdiff
dig
domain_test.sh
elfedit
eu-addr2line
eu-ar
eu-elfcmp
eu-elfcompress
eu-elflint
eu-findtextrel
eu-make-debug-archive
eu-nm
eu-objdump
eu-ranlib
eu-readelf
eu-size
eu-stack
eu-strings
eu-strip
eu-unstrip
file
fio
fix_idmap.sh
free
gcore
gdb
gdbserver
getcap
getpcaps
gprof
iftop
iostat
iotop
iperf
iperf3
kill
killall
ld
ld.bfd
ldd
log-analyzer.sh
lsof
ltrace
mpstat
name2addr
ncat
ndisc6
nethogs
nm
nmap
nping
nslookup
objcopy
objdump
perf-check.py
pgrep
pidof
pidstat
ping
ping6
pkill
pmap
ps
pstree
pwdx
ranlib
rarpd
rdisc
rdisc6
readelf
rltraceroute6
run
sa1
sa2
sadc
sadf
sar
setcap
sid2ugid.sh
size
slabtop
sockstat
speedtest-cli.py
strace
strings
strip
sysctl
sysstat
tcpdump_wrapper
tcpspray
tcpspray6
tcptraceroute6
telnet
tload
tmux
top
tracepath
traceroute6
tracert6
uptime
vmstat
w
watch
zblacklist
zmap
ztee
Comments

Etsy is also in the progress of enshittyfication?

Photo by Andrea Piacquadio: https://www.pexels.com/photo/young-annoyed-female-freelancer-using-laptop-at-home-3808008/

Amber McDaniel from SustainableJungle.com made a comprehensive video about Etsy and the downward spiral the platform seems to be locked-in. The developments, changes in processes etc. she describes clearly shout "Enshittyfication" to me.

If you are interested in the details hop over to Youtube and watch here video:

Source: https://www.youtube.com/watch?v=lSyEQAWLQbk

Comments

De mortuis nihil nisi bene

Photo by Veronika Valdova: https://www.pexels.com/photo/cemetery-of-fallen-soldiers-and-veterans-930711/

This is a Latin saying commonly translated to "Speak no ill of the dead." And I somewhat agree with that, however, due to a recent event in Germany I realized that I apply this behaviour in a more contextualized way.

But what happened? Ursula Haverbeck died. She was one of Germany's most known holocaust deniers. Despite being born in 1928 and therefore must having experienced - or at least heard of - the horrors first-hand. She must have seen people vanishing at night. Burning shops from "unwanted people" etc.

Yet she denied the holocaust publicly several times - which is a crime punishable by law in Germany. And to prison she went. I think between 3 to 5 times. For a sentence of, in total, 4 years.

Now she is dead at the age of 96.

And of course there are many jokes about her dead, people being generally happy that this mean-spirited woman is gone, etc. and so on. Just the Internet being ... well, The Internet.

Personally I smiled about some remarks or jokes but saw a line crossed when people were proposing to do illegal things to her grave. That's definitely against too many of my personal viewpoints. No matter if you believe in (a/any) god at all, our of which faith you are, a graveyard is sacred ground. A place where the living can meet the dead on a highly personal level. To ease the sorrow of a lost one. Completely disconnected from any religious dogmas or viewpoints - no matter if you share the same faith as the deceased person or not.
Religious arguments aside: Desecrating just one grave affects all people who have a connection to this graveyard. Totally not acceptable.

However there are many people who post comments with "Speak no ill of the dead." in order to ask people to stop making fun of her. And the common reply is: "There is nothing wrong in telling the truth about a dead person."

And I second this. We do not speak well of many people from the history of mankind either. Of course Hitler & Stalin immediately come to mind.
Well, certain people do, of course. But most people will be very determined in what they think of such people.

So, yes. Say anything about a dead person. As long as it is true. But keep in mind to whom you are speaking.

And this is what I realized. When I am at a funeral I won't go to the griefing partner/family-member/whomever and tell this person: "Ah, well you know.. I never really like X anyway." No, you won't. Common courtesy. Not the time nor the place to play games or live your personal vendetta. And if you can't bring yourself to not say anything like this: Be a nice human being and don't show up at all. Sometimes staying away from a funeral you have been invited to already says more than enough.

Maybe you would state that you will still miss this person - despite giving you hard times every now and then. Again focusing on the good. And this should be fine. As usually the bereaved know the character of the deceased very well for themselves.

For me, the saying therefore reads as: "Speak no lie of the dead and mind who you are talking to."

If we can collectively agree on this, than the Internet will be a better place.

Comments

Howto properly split all logfile content based on timestamps - and realizing my own fallacy

Photo by Mikhail Nilov: https://www.pexels.com/photo/person-in-black-hoodie-using-a-computer-6963061/

I use a Pi-hole for DNS based AdBlocking in my home network. Additionally I installed Unbound as recursive DNS resolver on it. Meaning: I can use the RaspberryPi in my network at home as the DNS server for all my devices. This way I don't have to use the DNS-Servers of my ISP granting me some additionally privacy. Additionally I can see which DNS queries are sent by each device. Leading to surprising revelations.

However recently my internet connection was interrupted and afterwards I noticed that I couldn't access any site or services where I used a domain or hostname to connect to. And while the problem itself (dnsmasq: Maximum number of concurrent DNS queries reached (max: 150)) was fixed easily with a simple restart of the unbound service, I noticed that the /var/log/unbound/unbound.log logfile was uncompressed, unrotated and 3.3 gigabyte in size. Whoops. That happens when no logrotate job is present.

Side gig: A logrotate config for Unbound

Fixing this issue was rather easy. A short search additionally revealed that unbound-control has a log_reopen option which is a good idea to trigger after the logrotate. This way Unbound properly closes old filehandles and uses the new logfile.

root@pihole:~# cat /etc/logrotate.d/unbound
/var/log/unbound/unbound.log {
        monthly
        missingok
        rotate 12
        compress
        delaycompress
        notifempty
        sharedscripts
        create 644
        postrotate
                /usr/sbin/unbound-control log_reopen
        endscript
}

But wait, there is more

However I had it on my list to dig deeper into the dnsmasq: Maximum number of concurrent DNS queries reached (max: 150) error in order to better understand the whole construct of Pi-hole, dnsmasq and Unbound.

However, the logfile was way too big to work conveniently with it. 49.184.687 lines are just too much. Especially on a RaspberryPi with the, in comparison, limited CPU power. Now I could have just split it up after n lines using split -l number-of-lines but that is:

  • Too easy and
  • Did I encounter the need for a script which splits logfile lines based on a range of timestamps more often in the recent time

How to properly split a logfile - and overcomplicating stuff

Most of the unbound logfile lines will have the Unix timestamp in brackets, followed by the process name, the log level the message belongs too and the actual message.

root@pihole:~# head -n 1 /var/log/unbound/unbound.log
[1700653509] unbound[499:0] debug: module config: "subnetcache validator iterator"

However some multi-line message wont follow this format:

[1700798246] unbound[1506:0] info: incoming scrubbed packet: ;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 0
;; flags: qr aa ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
chat.cdn.whatsapp.net.  IN      A

;; ANSWER SECTION:
chat.cdn.whatsapp.net.  60      IN      A       157.240.252.61

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:
;; MSG SIZE  rcvd: 55

[1700798246] unbound[1506:0] debug: iter_handle processing q with state QUERY RESPONSE STATE

This means we need the following technical approach:

  1. Generate the Unix-timestamp for the first day in a month at 00:00:00 o'clock
    • Alternatively formulated: The Unix-timestamp for the first second of a month
  2. Generate the Unix-timestamp for the last day of the month at 23:59:59 o'clock
    • The last second of a month
  3. Find the first occurrence of the timestamp from point 1
  4. Find the last occurrence of the timestamp from point 2
  5. Use sed to move the lines for each month into a separate logfile

I will however also show an awk command on how to filter based on the timestamps, useful for logfiles where every line is prefix with a timestamp.

Calculating with date

Luckily date is powerful and easy to use for date calculations. %s gives us the Unix timestamp. We do not need to specify hours:minutes:seconds as date automatically takes 00:00:00 for these values. Automatically giving us the first second of a day. And date also takes care of leap years and possible a lot of other nuisances when it comes to time and date calculations.

To get the last second of a month we simply take the first day of the month, add a month and subtract one second. It can't be easier.

# Unix timestamp for the first second in a month
user@host:~$ date -d "$(date +%Y/%m/01)" "+%Y/%m/%d %X - %s"
2024/11/01 00:00:00 - 1730415600

# Unix timestamp for the last second in a month
user@host:~$ date -d "$(date +%Y/%m/01) + 1 month - 1 second" "+%Y/%m/%d %X - %s"
2024/11/30 23:59:59 - 1733007599

To verify the value we can use this for-loop. It will give us all the date and timestamps we need to confirm that our commands are correct.

user@host:~$ for YEAR in {2023..2024}; do for MONTH in {1..12}; do echo -n "$(date -d "$(date +$YEAR/$MONTH/01)" "+%Y/%m/%d %X - %s")  "; date -d "$(date +$YEAR/$MONTH/01) + 1 month - 1 second" "+%Y/%m/%d %X - %s"; done; done
2023/01/01 00:00:00 - 1672527600  2023/01/31 23:59:59 - 1675205999
2023/02/01 00:00:00 - 1675206000  2023/02/28 23:59:59 - 1677625199
2023/03/01 00:00:00 - 1677625200  2023/03/31 23:59:59 - 1680299999
2023/04/01 00:00:00 - 1680300000  2023/04/30 23:59:59 - 1682891999
2023/05/01 00:00:00 - 1682892000  2023/05/31 23:59:59 - 1685570399
2023/06/01 00:00:00 - 1685570400  2023/06/30 23:59:59 - 1688162399
2023/07/01 00:00:00 - 1688162400  2023/07/31 23:59:59 - 1690840799
2023/08/01 00:00:00 - 1690840800  2023/08/31 23:59:59 - 1693519199
2023/09/01 00:00:00 - 1693519200  2023/09/30 23:59:59 - 1696111199
2023/10/01 00:00:00 - 1696111200  2023/10/31 23:59:59 - 1698793199
2023/11/01 00:00:00 - 1698793200  2023/11/30 23:59:59 - 1701385199
2023/12/01 00:00:00 - 1701385200  2023/12/31 23:59:59 - 1704063599
2024/01/01 00:00:00 - 1704063600  2024/01/31 23:59:59 - 1706741999
2024/02/01 00:00:00 - 1706742000  2024/02/29 23:59:59 - 1709247599
2024/03/01 00:00:00 - 1709247600  2024/03/31 23:59:59 - 1711922399
2024/04/01 00:00:00 - 1711922400  2024/04/30 23:59:59 - 1714514399
2024/05/01 00:00:00 - 1714514400  2024/05/31 23:59:59 - 1717192799
2024/06/01 00:00:00 - 1717192800  2024/06/30 23:59:59 - 1719784799
2024/07/01 00:00:00 - 1719784800  2024/07/31 23:59:59 - 1722463199
2024/08/01 00:00:00 - 1722463200  2024/08/31 23:59:59 - 1725141599
2024/09/01 00:00:00 - 1725141600  2024/09/30 23:59:59 - 1727733599
2024/10/01 00:00:00 - 1727733600  2024/10/31 23:59:59 - 1730415599
2024/11/01 00:00:00 - 1730415600  2024/11/30 23:59:59 - 1733007599
2024/12/01 00:00:00 - 1733007600  2024/12/31 23:59:59 - 1735685999

To verify we can do the reverse (Unix timestamp to date) with the following command:

user@host:~$ date -d @1698793200
Wed  1 Nov 00:00:00 CET 2023

Solution solely working on timestamps

As the logfile timestamp is enclosed in brackets we need to tell awk to treat either [ or ] as a field separator. Then we can use awk to check if the second field is in a given time frame. For the first test run we define the variables manually in our shell and adjust the date commands to only output the Unix timestamp.

And as the logfile starts in November 2023 I set the values accordingly. awk then conveniently puts all lines whose timestamp is between these to values into a separate logfile.

user@host:~$ YEAR=2023
user@host:~$ MONTH=11
user@host:~$ FIRST_SECOND=$(date -d "$(date +$YEAR/$MONTH/01)" "+%s")
user@host:~$ LAST_SECOND=$(date -d "$(date +$YEAR/$MONTH/01) + 1 month - 1 second" "+%s")
user@host:~$ awk -F'[\\[\\]]' -v MIN=${FIRST_SECOND} -v MAX=${LAST_SECOND} '{if($2 >= MIN && $2 =< MAX) print}' /var/log/unbound/unbound.log >> /var/log/unbound/unbound-$YEAR-$MONTH.log

And this would already work fine, if every line would start with the timestamp. As this is not the case we need to add a bit more logic.

So the resulting script would look like this:

user@host:~$ cat date-split.sh
#!/bin/bash
# vim: set tabstop=2 smarttab shiftwidth=2 softtabstop=2 expandtab foldmethod=syntax :

# Split a logfile based on timestamps

LOGFILE="/var/log/unbound/unbound.log"
AWK="$(command -v awk)"
GZIP="$(command -v gzip)"

for YEAR in {2023..2024}; do
  for MONTH in {1..12}; do

    # Logfile starts November 2023 and ends November 2024 - don't grep for values before/after that time window
    if  [[ "$YEAR" -eq 2023 && "$MONTH" -gt 10 ]] ||  [[ "$YEAR" -eq 2024 && "$MONTH" -lt 12 ]]; then

      # Debug
      echo "$YEAR/$MONTH"

      # Calculate first and last second of each month
      FIRST_SECOND="$(date -d "$(date +"$YEAR"/"$MONTH"/01)" "+%s")"
      LAST_SECOND="$(date -d "$(date +"$YEAR"/"$MONTH"/01) + 1 month - 1 second" "+%s")"

      # Export variables so the grep in the sub-shells have this value
      export FIRST_SECOND
      export LAST_SECOND

      # Split logfiles solely based on timestamps
      awk -F'[\\[\\]]' -v MIN=${FIRST_SECOND} -v MAX=${LAST_SECOND} '{if($2 >= MIN && $2 <= MAX) print}' unbound.log >> "unbound-$YEAR-$MONTH.log"

      # Creating all those separate logfiles will probably fill up our diskspace
      #  therefore we gzip them immediately afterwards
      "$GZIP" "/var/log/unbound/unbound-$YEAR-$MONTH.log"

    fi

  done;
done

However, this script is vastly over-engineered. Why? Read on.

StackOverflow to the rescue

I still had the problem with the multi-line log messages. At first I wanted to use grep to get the matching first and last line numbers with head and tail. But uh.. Yeah, I had a fallacy here. As still wouldn't have worked with multi-line logmessages without a timestamp. Also using grep like this is highly inefficient. While it would be fine for a one-time usage script I still hit a road block.

I just wasn't able to get awk to do what I wanted and I resorted to asking my question on StackOverflow. Better to get the input from others then wasting a lot of time.

awk to the rescue

It was only through the answer that I realized that my solution was a bit over-engineered. Why use date if you can use strftime to calculate the year and month from the timestamp directly? The initial answer was:

awk '
$1 ~ /^\[[0-9]+]$/ {
  f = "unbound-" strftime("%m-%Y", substr($1, 2, length($1)-2)) ".log"
  if (f != prev) close(f); prev = f
}
{
  print > f
}' unbound.log

How this works has been explained in detail on StackOverflow, so I just copy & paste it here.

For each line which first field is a [timestamp] (that is, matches regexp ^\[[0-9]+]$), we use substr and length to extract timestamp, strftime to convert it to a mm-YYYY string and assign "unbound-mm-YYYY.log" to variable f. In the second block, that applies to all lines, we print the current line in file f. Note: contrary to shell redirections, in awk, print > FILE appends to FILE.

Edit: as suggested by Ed Morton closing each file when we are done with it should significantly improve the performance if the total number of files is large. if (f != prev) close(f); prev = f added. Ed also noted that escaping the final ] in the regex is useless (and undefined behavior per POSIX). Backslash removed.

And this worked flawlessly. The generated monthly logfiles from my testfile matched exactly the line-numbers per month. Even multi-line log messages and empty lines were included.

All I then did was adding gzip to compress the files directly before the next file is created. Just to prevent filling up the disk completely. Additionally I change the filename from unbound-MM-YYYY.log to unbound-YYYY-MM.log. Yes, the logfile name won't work with logrotate. But I just need it to properly dig through the files and the Year-Month naming will be of great help here. Afterwards I don't need them anymore and will delete them. So this was none of my concern.

This was my new working solution:

awk '$1 ~ /^\[[0-9]+]$/ {
  f = "unbound-" strftime("%Y-%m", substr($1, 2, length($1)-2)) ".log"
  if (f != prev) {
    if (prev) system("gzip " prev)
    close(prev)
    prev = f
  }
}
{
  print > f
}
END {
  if (prev) system("gzip " prev)
}' unbound.log

No bash script with convoluted logic needed. And easily useable for other logfiles too. Just adopt the starting regular expression to match the one the logfile uses and adopt the logic for strftime so the proper timestamp can be created.

Sometimes it's better to ask other people. 😄

Comments

"It's always DNS."

Photo by Visual Tag Mx: https://www.pexels.com/photo/white-and-black-scrabble-tiles-on-a-white-surface-5652026/

"It's always DNS."
   - Common saying among system administrators, developers and network admins alike.

Recently my blogpost about Puppet's move to go semi-open-source gained some attention and I grew curious where it was mentioned and what people thought about it. Therefore I did a quick search for "puppet goes enshittyfication" and was presented with a few results. Mostly Mastodon posts but also one website from Austria (the one without Kangaroos 😁). Strangely they also copied the site title, not just the texts' title, as it showed up as "Feuerfest | Puppet goes enshittyfication".

Strange.

I clicked on it and received a certificate warning that the domain in the certificate doesn't match the domain I'm trying to visit.

I ignored the warning and was presented with a 1:1 copy of my blog. Just the images were missing. Huh? What? Is somebody copying my blog?

A short whois on the domain name revealed nothing shady. It belonged to an Austrian organization whose goal it is to inform about becoming a priest of the catholic church and help seminarians. Ok, so definitely nothing shady.

I looked at the certificate and.. What? It was issued for "admin.brennt.net" by Let's Encrypt. That shouldn't be possible from all I know, as that domain is validated to my Let's Encrypt account. I checked the certificates fingerprints and.. They were identical, huh?

That would mean that either someone managed to get the private key for my certificate (not good!) or created a fake private key which somehow a webserver accepted. And wouldn't Firefox complain about that or would the TLS handshake fail? (If somebody knows the answer to this, please comment. Thank you!)

I was confused.

Maybe the IP/hoster of the server will shed some light on this?

Aaaaand it was the current IP of this blog/host. Nothing shady. Nothing strange. Just orphaned DNS-records from a long-gone web-project.

As I know that Google - and probably any other search engine too - doesn't like duplicate content I helped myself with a RewriteRule inside this vHost.

# Rewrite for old, orphaned DNS records from other people..
RewriteEngine On
<If "%{HTTP_HOST} == 'berufungimzentrum.at'">
    RewriteRule "^(.*)$" "https://admin.brennt.net/please-delete.txt"
</If>

Now everyone visiting my site via "that other domain" will receive a nice txt-file asking to please remove/change the DNS entries.

It certainly IS always DNS.

EDIT: As I regularly read the logfiles of my webserver I noticed that there are additional domains who point to this host.. So I added additional If-Statements to my vHost-config and added the domains to the txt-file. 😇

Comments

Puppet goes enshittyfication (Updated)

Photo by Pixabay: https://www.pexels.com/photo/computer-screen-turned-on-159299/

This one came unexpected. Puppetlabs, the company behind the configuration management software Puppet, was purchased by Perforce Software in 2022 (and renamed to "Puppet by Perforce") and now, in November 2024 we start to see the fallout of this.

As Puppetlabs announced on November 7th 2024 in a blogpost they are, to use an euphemism: "Moving the Puppet source code in-house."

Or in their words (emphasizes by me):

In early 2025, Puppet will begin to ship any new binaries and packages developed by our team to a private, hardened, and controlled location. Our intention with this change is not to limit community access to Puppet source code, but to address the growing risk of vulnerabilities across all software applications today while continuing to provide the security, support, and stability our customers deserve.

They then go on in length to state why this doesn't affect customers/the community and that the community still can get access to that private, hardened and controlled location via a separate "development license (EULA)". However currently no information about the nature of that EULA is known and information will be released in early 2025 so after the split was made.

To say it bluntly: I call that bullshit. The whole talk around security and supply-chain risks is non-sense. If Puppet really wanted to enhance the technical security of their software product they could have achieved so in a myriad of other ways.

  • Like integrating a code scanner into their build pipelines
  • Doing regular code audits (with/from external companies)
  • Introducing a four-eyes-principle before commits are merged into the main branch
  • Participating in bug-bounty programs
  • And so on...

There is simply no reason to limit the access to the source-code to achieve that goal. (And I am not even touching the topic of FUD or how open source enables easier & faster spotting of software defects/vulnerabilities.) Therefore this can only be viewed as a straw-man fallacy type of expression to masquerade the real intention. I instead see it as what it truly is: An attempt to maximize revenue. After all Perforce wants to see a return for their investment. And as fair as this is, the "how" lets much to be desired...

We already have some sort-of proof. Ben Ford, a former Puppet employee wrote a blogpost Everything is on fire.... in mid October 2024 stating his negative experience with the executives and vice-presidents of Puppet he made in 2023 when he tried to explain the whole community topic to them (emphasizes by me):

"I know from personal experience with the company that they do not value the community for itself. In 2023, they flew me to Boston to explain the community to execs & VPs. Halfway through my presentation, they cut me off to demand to know how we monetize and then they pivoted into speculation on how we would monetize. There was zero interest in the idea that a healthy community supported a strong ecosystem from which the entire value of the company and product was derived. None. If the community didn’t literally hand them dollars, then they didn’t want to invest in supporting it."

I find that astonishing. Puppet is such a complex piece of configuration management software and has so many community-developed tools supporting it (think about g10k) that a total neglect of everything the community has achieved is mind-blowingly short-sighted. Puppet itself doesn't manage to keep up with all the tools they have released in the past. The ways of tools like Geppetto or the Puppet Plugin for IntellJ IDEA speak for themselves. Promising a fully-fledged Puppet IDE based on Eclispe and then letting it rot? No official support from "Puppet by Perforce" for one of the most used and commercially successful integrated development environment (IDE)? Wow. This is work the community contributes. And as we now know Puppet gives a damn about that. Cool.

EDIT November 13th 2024: I forgot to add some important facts regarding Puppets' ecosystem and the community:

I consider at least the container images to be of utmost priority for many customers. And neglecting all important tools around your core-product isn't going to help either. These are exactly the type of requirements customers have/questions they ask.

  • How can we run it ourself? Without constantly buying expensive support.
  • How long will it take until we build up sufficient experience?
  • What technology knowledge do our employees need in order to provide a flawless service?
  • How can we ease the routine tasks? / What tools are there to help us during daily business?

Currently Puppet has a steep learning curve which is only made easier thanks to the community. And now we know Perforce doesn't see this as any kind of addition to their companies' value. Great.

EDIT END

The most shocking part for myself was: That the Apache 2.0 license doesn't require that the source code itself is available. Simply publishing a Changelog should be enough to stay legally compliant (not talking about staying morally compliant here...). And as he pointed out in another blogpost from November 8th, 2024 there is reason they cannot change the license (emphasizes by me to match the authors'):

"But here’s the problem. It was inconsistently maintained over the history of the project. It didn’t even exist for the first years of Puppet and then later on it would regularly crash or corrupt itself and months would go by without CLA enforcement. If Perforce actually tried to change the license, it would require a long and costly audit and then months or years of tracking down long-gone contributors and somehow convincing them to agree to the license change.

I honestly think that’s the real reason they didn’t change the license. Apache 2 allows them to close the source away and only requires that they tell you what they changed. A changelog might be enough to stay technically compliant. This lets them pretend to be open source without actually participating."

I absolutely agree with him. They wanted to go closed-source but simply couldn't as previously they never intended to. Or as someone on the internet said: "Luckily the CLA is ironclad." So instead they did what was possible and that is moving the source-code to an internal repository. Using that as the source for all official Puppet packages - but will we as Community still have access to those packages?

For me, based on how the blogpost is written, I tend to say: No. Say goodbye to https://yum.puppetlabs.com/ and https://apt.puppetlabs.com/. Say goodbye to an easy way of getting your Puppet Server, Agent and Bolt packages for your Linux distribution of choice.

Update 15th November 2024: I asked Ben Ford in one of his Linkedin posts if there is a decision regarding the repositories and he replied with: "We will be meeting next week to discuss details. We'll all know a bit more then." As good as it is that this topic isn't off the table it still adds to the current uncertainty. Personally I would have thought that those are the details you finalize before making such an announcement.. But ah well, everyone is different.. Update End

A myriad of new problems

This creates a myriad of new problems.

1. We will see a breakline between "Puppet by Perforce"-Puppet packages and Community-packages in technical compatibility and, most likely, functionality too.

This mostly depends on how well Puppet contributes back to the Open Source repository and/or how well-written the Changelog is and regarding that I invite you to check some of their release notes for new Puppet server versions (Puppet Server 7 Release Notes / Puppet Server 8 Release Notes) although it got better with version 8... Granted they already stated the following in their blogpost (emphasizes by me):

We will release hardened Puppet releases to a new location and will slow down the frequency of commits of source code to public repositories.

This means customers using the open source variant of Puppet will be in somewhat dangerous waters regarding compatibility towards the commercial variant and vice-versa. And I'm not speaking about the inter-compatibility between Puppet servers from different packages alone. Things like "How the Puppet CA works" or "How are catalogues generated" etc. Keep in mind: Migrating from one product to the other can also get significantly harder.

This could even affect Puppet module development in case the commercial Puppet server contains resource types the community based one doesn't or does implement them slightly different. This will affect customers on both sides badly and doesn't make a good look for Puppet. Is Perforce sure this move wasn't sponsored by RedHat/Ansible? Their biggest competitioner?

2. Documentation desaster

As bad as the state of Puppet documentation is (I find it extremely lacking in every aspect) at least you have one and it's the only one. Starting 2025 we will have two sets of documentation. Have fun working out the kinks..

Additionally documentation wont get better. Apparently this source states that "Perforce actually axed our entire Docs team!" How good will a Changelog or the documentation be when it's nobody's responsibility?

3. Community provided packages vs. vendor packages

Nearly all customers I worked at have some kind of policy regarding what type of software is allowed on a system and how that is defined. Sometimes this goes so far as "No community supported software. Only software with official vendor support". Starting 2025 this would mean these customers would need to move to Puppet Enterprise and ditch the community packages. The problem I foresee is this: Many customers already use Ansible in parallel and most operations teams are tired having to use two configuration management solutions. This gives them a strong argument in favour of Ansible. Especially in times of economic hard-ship and budget cuts.

But again: Having packages from Puppet itself at least makes sure you have the same packages everywhere. In 2025 when the main, sole and primary source for those packages goes dark numerous others are likely to appear. Remember Oracles' move to make the Oracle JVM a paid-only product for commercial use? And how that fostered the creation of dozens of different JVMs? Yeah, that's a somewhat possible scenario for the Puppet Server and Agent too. Although I doubt we will ever see more than 3-4 viable parallel solutions at anytime given the amount of work and that Puppet isn't that widely required as a JVM is. Still this poses a huge operational risk for every customer.

4. Was this all intentional?

I'm not really sure if Perforce considered all this. However they are not stupid. They sure must see the ramifications of their change. And this will lead to customers asking themself ugly questions. Questions like: "Was this kind of uncertainty intentional?" This shatters trust on a basic level. Trust that might never be retained.

5. Community engagement & open source contributors

Another big question is community engagement. We now have a private equity company which thinks nothing about the community and the community knows this. There is already a drop in activity since the acquisition of Puppet by Perforce. I think this trend will continue. After all, with the current situation we will have a "We take everything from the community we want, but decide very carefully what and if we are giving anything back in return." This doesn't work for many open source contributors. And it is the main reason why many will view Puppet as being closed source from 2025 onward. Despite being technically still open source - but again the community values moral & ethics higher than legal correctness.

So, where are we heading?

Personally I wouldn't be too surprised if this is the moment where we are looking back to in the future and say: "This is the start of the downfall. This is when Puppet became more and more irrelevant until it's demise." As my personal viewpoint is that Puppet lacked vision and discipline for some years. Lot's of stuff was created, promoted and abandoned. Lot's of stuff was handed-over to the community to maintain it. But still the ecosystem wasn't made easier, wasn't streamlined. Documentation wasn't as detailed as it should be. Tools and command-line clients lacked certain features you'd have to work around yourself. And so on.. I even ditched Puppet for my homelab recently in favour of Ansible. The overhead I had to carry out to keep it running, the work on-top which was generated by Puppet itself, just to keep it running. Ansible doesn't have all of that.

In my text Get the damn memo already: Java11 reached end-of-life years ago I wrote:

If you sell software, every process involved in creating that piece of software should be treated as part of your core business and main revenue stream. Giving it the attention it deserves. If you don't, I'm going to make a few assumptions about your business. And those assumptions won't be favourable.

And this includes the community around your product. Especially more so for open source software.

Second I won't be surprised if many customers don't take the bite, don't switch to a commercial license, ride Puppet as long as it is feasible and then just switch to Ansible.

Maybe we will also see a fork. Giving the community the possibility to break with Puppet functionality. Not having to maintain compatibility any longer.

Time will tell.

New developments

This was added on November 15th: There are now the first commnity-build packages available. So looks like a fork is happening.

Read: https://overlookinfratech.com/2024/11/13/fork-announce/

EDIT: A newer post regarding the developments around the container topic and fork is here: Puppet is dead. Long live OpenVox!

Comments