Variadic C arguments and other gcc tricks
Q: How do you write a debug helper function passing through printf()
like data?
A: Use a combination of macros and variadic functions combined with the power of gcc extensions.
Q: How do you write a debug helper function passing through printf()
like data?
A: Use a combination of macros and variadic functions combined with the power of gcc extensions.
Several years ago I did setup OwnCloud. I managed users and groups in OpenLDAP, as I had another use-cases, where I needed that information for authentication.
Several years later I switched to NextCloud and got rid of that other use-case. Managing users and groups have become a pain in LDAP: I have to use CLI tools instead of the GUI. While I can do it, others don’t like it. So I would like to uninstall OpenLDAP.
Nicols ask the same question and developed a solution: Import LDAP users & get rid of LDAP It is a bit outdated and contains some errors. So here is my step-by-step guide.
Q: How do I recursively find all shell scripts in my current working directory?
A: Search for the hash-bang line:
$ git -c grep.fallbackToNoIndex=yes grep -lPe '\A#!\s*/bin/([bd]?a)?sh\b'
I work with GitLab, where I often have to create Merge Requests.
You can do this using the browser based graphical user interface, or from the command line when doing a git push
:
You can specify several push options for merge requests via the argument -o
:
merge_request.create
:
Create a new merge request for the pushed branch.merge_request.target=<branch_name>
:
Set the target of the merge request to a particular branch.merge_request.merge_when_pipeline_succeeds
:
Set the merge request to merge when its pipeline succeeds.merge_request.remove_source_branch
:
Set the merge request to remove the source branch when it’s merged.There are many more.
Some time ago I received a new Lenovo P14s notebook. My previous L470 worked very well for a long time, so I only switch to the new model beginning this year. Since then I experienced regular stalls: Mostly during our daily video conferences the laptop locked up for some minutes; only after 1-2 minutes I was able to resume my work, but found some process(es) gone.
I want to clone multiple virtual machines belonging together. They internally communicate among themselves using their static IP addresses. Changing the network configuration per clone is not an option. On the other hand I want to connect to these machines from the outside.
┌──────────────────────host─────────────────────┐
│ ┌───────────env1────────────┐ │
│ │ ┌───vm1.2──┐ ┌───vm1.3──┐ │ │
│ │ │ 10.0.0.2 │ │ 10.0.0.3 │ ├──┐ │
│ │ └──────────┘ └──────────┘ │ │ │
│ └───────────────────────────┘ │ │
│ │ │
│ ┌───────────env2────────────┐ │ │
│ │ ┌───vm2.2──┐ ┌───vm2.3──┐ │ ├───────┐ │
│ │ │ 10.0.0.2 │ │ 10.0.0.3 │ ├──┤ magic ├─eth0─┼─
│ │ └──────────┘ └──────────┘ │ ├───────┘ │
│ └───────────────────────────┘ │ │
│ │ │
│ ┌───────────env3────────────┐ │ │
│ │ ... ├──┘ │
│ └───────────────────────────┘ │
└───────────────────────────────────────────────┘
In my previous blog post Python rich comparison I looked at simplifying the comparison of objects.
Using NotImplemented in boolean context has been deprecated since Python 3.9:
As bool(NotImplemented) is True
this resulted in many wrong implementations, including mine.
So how do you correctly implement rich comparison?
Univention Corporate Server (UCS) is a Debian GNU/Linux based enterprise operating system. For automatic installation testing the Python package vncdotool is used to click through the installation process running inside a virtual machine using QEMU. Most of the time this worked without problems but recently our tests were failing on a regular basis without any major change to our code base. Any expert will already think of timing issues and at the end it actually will be.
Python wheels are a distribution format for Python packages defined by PEP-427. As long as your package is simple and just consists of a bunch of Python files, creating and shipping a source only distribution is probably fine. But as soon your Python package build process takes time or needs (many) other dependencies to build — or even worse — it needs some (C-)compiler and libraries plus their development headers, those packages become a pain.
Today UCS@school had an interesting issue, where the Kelvin REST API pipeline failed, specifically the build job building a Docker image using Kaniko. This gist of the error was a permission error:
Q: How do I resize the root file system of my UCS VM?
GitLab pipeline can run for many reasons, which are indicated via the CI/CD variable CI_PIPELINE_SOURCE
:
Gitlab 103: Kaniko image building described, how to build Docker respective OCI images using Kaniko.
Compared to Docker-in-Docker it has one drawback:
speed — at least when your Dockerfile
contains RUN
commands, which take a long time like doing an apt-get install
with many or large packages.
Debian’s package manager APT is famous for its inter-package dependency resolving mechanism:
Long before rpm
based distributions learned how to install dependant packages automatically Debian did do this for many years.
You simply can install a high-level package using apt-get install $pkg
, which will then automatically resolve all dependencies:
Dependant packages are downloaded and install along automatically.
This works very well when you just use packages from a single consistent source like the stable Debian repository. It mostly also works with multiple repositories, but from time to time the resolver does strange things.
Here at Univention GmbH we build our own packages. Therefore it is essential for our customers that we get the dependencies right. Today we had the strange behavior, where one of our packages could not be upgraded: APT decided to refuse the package from getting installed. Simplify specifying one additional dependency on the command line made it work.
So what happened and why did APT refuse the initial command?
Dependency resolution has some very useful information on how the resolver works:
APT works in its internal resolver in two stages: First all packages are visited and marked for installation, keep back or removal. Option
Debug::pkgDepCache::Marker
shows this. This also decides which packages are to be installed to satisfy dependencies, which can be seen byDebug::pkgDepCache::AutoInstall
. After this is done, we might be in a situation in which two packages want to be installed, but only one of them can be. It is the job of thepkgProblemResolver
to decide which of two packages ‘wins’ and can therefore decide what has to happen. You can see the contenders as well as their fight and the resulting resolution withDebug::pkgProblemResolver
.
On a regular basis I have to scan some paper documents. For the scanning I still use xsane (X Scanner Access Now Easy) for that. Afterwards I used GIMP (GUN Image Manipulation Program) to do the post processing:
This normally reduced the file size by a factor of 10 from 10 MiB per page to roughly 1 MiB per page. While it worked for me it was a lot of work, which took its time.
Locking files in Linux is tricky - not because it is complex, but complicated due to the many variants.
First of all you have different kinds:
mand
.For advisory locks you have multiple types in Linux:
Basically they are incompatible with each other and your applications should agree to use only one.
Variant | Origin | NFS | range | associated | fork() |
auto released |
---|---|---|---|---|---|---|
FLOCK | BSD | no¹ | file | open FD | inherited | last FD closed |
POSIX | POSIX | yes | bytes | pid,inode | dropped | any FDs closed |
OFDLCK | Linux | yes | bytes | open FD | inherited | last FD closed |
Following Gitlab 101: Container usage and Gitlab 102: container followup let’s have a look at Docker images itself, also known as OCI Images. If you want to know the gory details have a look at the image specification yourself.
Gitlab 102: container followup briefly describes building Docker images with Kaniko instead of Docker in docker. Let’s take a look at some common practices to build images.
Continuing Gitlab 101: Container usage there are some news:
In the early days of K&R C programming the type for functions parameters was optional and declared separately:
void old(a, b, c)
int a;
bool b;
char *c;
{
printf("a=%i b=%d c=%p\n", a, b, c);
}
Q: How to convert from legacy MBR to GPT required for UEFI?
A: Follow ServerFault: How do I convert my linux disk from MBR to GPT with UEFI
grub-pc
for booting.
You can skip this step if you convert to GPT and grub-efi-amd64-bin
at the same time.Gitlab consists of multiple parts: Gitlab runners are the work horses, which execute the jobs of a pipeline. Gitlab runners have different flavors:
During Debian package installation, upgrade, downgrade and remove the so called Debian Package maintainer scripts are called before and after certain actions:
Q: How can I install UCS packages from apt/ (on demand)?
argparse has superseded optparse, which is deprecated since Python 3.2 and might get removed in the future.
Many of our scripts have already been migrated, but argparse
and the migration has several pitfalls.
This was already mentioned in one of my previous posts Python: optparse vs. argparse.
Several flaws were found in GRUB, the GRand Unified Boot-Loader in 2020 and 2021. These can be used for by-pass Secure Boot, which provides a secure path from booting the PC to running Linux: No unauthorized software like a virus should have a chance to get loaded before Linux has been loaded and started.
Q: How are Debian package version strings compared?
A: This is mandated by Debian Policy and dpkg
is considered the single truth of implementation.
Comparing Debian package version strings is not trivial:
many programs implement this themselves and get it wrong for corner cases — me included.
Therefor use dpkg –compare-versions or one of its wrappers, for example apt.apt_pkg.version_compare()
for Python or debversion
for PostgreSQL.
Continue reading if you want to understand comparing Debian package version strings yourself, which is important when you increment the version of UCS packages.
The format is:
[epoch:
]upstream-version[-
debian-revision]
Aus gegebenen Anlass, weil scheinbar die Basics fehlen:
How fast is string concatenation in Python?
a + b + c
"".join((a, b, c))
"%s%s%s" % (a, b, c)
"{}{}{}".format(a, b, c)
f"{a}{b}{c}"
c="";c+=x;c+=y;c+=z;c
You can install Debian packages using dpkg -i $pkg.deb
, but this low-level tool does not resolve inter-package dependencies.
This is the job of APT, the Advanced Packaging Tool.
It usually works on a set of packages, which are shipped in a package repository.
This has a Packages
file, which lists all binary packages included in the repository.
Basically it contains the concatenated package meta data from all packages.
In Python 3 gabt es mehrere wichtige Änderung bezüglich Dateien und Prozessen: Um aus open() zu zitieren:
I’m using docker on my notebook for development. An mentioned in UNIX 113: DocBook Docker images we already have several UCS images in docker-registry of many UCS releases and for different tasks:
In the UMC-server vs. python-notifier pullcord we had the situation, that an unknown process kept killing other processes from time to time and we had no idea, which process it was.
The Linux audit system can be used to collect important system events. It is often used for compliance with PCI DSS 3.1. But it is also useful for debugging certain problems, for example where you have to monitor an unknown number of processes to show a certain behavior. In our case an unknown process kept killing other processes form time to time.
At work we’re using DocBook for our product documentation. We have a tool for spell-checking our documents.
Solving this with Python is not easy for obscure reasons.
Continuing my GitLab and Kubernetes (k8s) odyssey from k8s @ Debian I’ve learned two things:
Recently I’ve been reeding books:
Q: Wie installiere ich die für den Bau des Debian-Pakets im aktuellen Arbeitsverzeichnis notwendigen Pakete?
docker
is nice to run application commands as you can put them into a container, which also includes the required dependencies.
This saves you from cluttering your notebook with a multitude of strange packages from Debian, PyPI, golang, … We’re already using this for running our DocBook toolchain or ucslint
and are in the process to convert ucs-ec2-tools
to this.
Recently I stumbled over the possibility to retro-actively modify the snapshot XML data of saved VMs. This is most helpful for fixing the fallout of Bug #50412, where several CPUs features related to “TSX” where disabled by the Linux kernel to prevent the TSX Asynchronous Abort vulnerability.
Python 3 has switch to Rich Comparisons.
With Python 2 is was enough to implement a single __cmp__(self, other)
method, now you have to implement
__lt__(self, other)
__le__(self, other)
__eq__(self, other)
__ne__(self, other)
__ge__(self, other)
__gt__(self, other)
__hash__(self)
@functools.total_ordering
helps with this, but this is still painful.
For historical reasons I have been using eCryptfs, a file system layer for encrypted files. It got removed from Debian Buster, but I’m still using it.
Man sollte mit __del__()
-Methoden in Python sehr aufpassen:
Working for libvirt
I had to add the Developer Certificate of Origin to several previous commits, where I forgot to directly use git commit --signoff
.
StackOverflow has that question, but it started missing -s
for --signoff
with -S
for --gpg-sign
.
Be careful when you switch from optparse.OptionParser to argparse.ArgumentParser as they use different defaults for action="store_true"
and action="store_false"
:
The former initializes the value to None
while the later one to the inverse of the desired action, that is to False
if action="store_true"
is used and vis-versa.
Q: Wie unterscheide in Upgrades von Neuinstallationen?
A: dpkg --compare-versions "$2" lt-nl "…"
Die Versionsnummer von Debian-Paketen baut sich nach folgendem Schema auf:
ldapsearch
hat einige nützliche Parameter:
Q: Gibt es eine empfohlene Schreibweise für die Einträge in debian/*
-Dateien?
I had to build a web camera for watching some newly hatched birds. From previous experiments I already had a spare Raspberry Pi wit an attached camera. Due to bandwidth limitations in the wireless network I wanted to host the resulting media on one of my public servers. I’m using ffmpeg with HLS streaming as this works in most browsers out-of-the-box.
Debians dpkg-buildpackage
has the annoying feature, that the build artifacts are placed in the parent directory.
Bug 657491 requested that feature in 2012, but there still is no such option.
While working on speeding up the build process I investigated, how that could be fixed or at least be worked around.
For my employee Univention I want to setup a Continuous Integration system to build Debian packages. We have been using our own build-system called Repo-NG based on pbuilder, which show their age. I tried several tricks to improve the build speed as we have to build many packages and many of them multiple times.
Ein Rätsel:
Q: Der OpenLDAP-Server liefert mir zu wenig Daten und ich kann oder will ihn aber im moment nicht neu starten. Was kann ich tun?
Wie in Python 3.3: unicode bereits beschrieben unterschiedet Python 2 deutlich strikter zwischen Unicode-Zeichenketten und Byte-Strings.
Das wirk sich auch auf LDAP aus und python-ldap ≥ 3 hat dafür zwei neuen Parameter bytes_mode
und bytes_strictness
bekommen, die das Verhalten bereits für Python 2 grundlegend ändert.
Ersterer kontrolliert primär das Ausgabeformat, zweiterer kontrolliert die akzeptierten Typen der Eingabeparameter.
Folgendes ist mit Python 3 syntaktisch nicht mehr erlaubt: ```python try: pass except: pass
In Python 2 sind Zeichenketten intern eine Ansammlung von Bytes, in Python 3 dagegen Unicode-Zeichen. Letztere gibt es auch schon in Python 2, nur musste man sie dort explizit als solche Deklarieren. Nun gilt es umgekehrt und man muss Bytes explizit in Python 3 deklarieren.
Python 3 verwendet öfters Iteratoren als Python 2, so lieferen dict().keys(), dict().values(), dict.items()
inzwischen Iteratoren statt Listen.
In Python 2 wurde dafür extra dict().iterkeys(), dict().itervalues(), dict().iteritems()
hinzugefügt, die es in Python 3 nicht mehr gibt.
Für den Vergleich von eigenen Objekten genügte es mit Python2 die Methode __cmp__(self, other)
zu implementieren, die einen Wert kleiner, gleich oder größer Null zurück gibt, je nach dem wie der Vergleich ausfällt.
Das erinnert sehr an die guten alten C-Zeiten.
Aus verschiedenen Gründen wurde das mit Python 3 geändert, u.a. möchte z.B. NumPy beim Vergleich von Vektoren kein einfaches bool
zurück geben, sondern einen Vektor komponentenweise vergleichen und selber einen Vektor mit dem Ergebnis pro Komponente zurückzugeben.
Das war mit der alten Syntax von __cmp__()
nicht machbar.
Q: Kennt ihr apt-transport-mirror
?
UCR implementiert einen Template-Mechanismus: Er ersetzt Platzhalter in der Vorlage durch die konfigurierten Werte (oder führt passenden Python-Code aus).
echo '@%@hostname@%@' | ucr filter
In vielen anderen Situationen wird gerne sed
(oder ähnliches) genutzt, um Platzhalter in anderen Dateien zu ersetzten:
echo '@XXX@' | sed -e "s/@XXX@/$(hostname)/g"
Bei dieser Art der Ersetzung übersieht man gerne, dass man dort eigentlich die Werte passend escapen muss, denn ein /
würde hier den sed-Befehl ändern.
I’m using MythTV for watching TV and videos. For that I have a separate HP micro server which 4 HDs. That system is quiet old and low-powered. Because of that I rip my DVDs on my new PC and copy over the files.
Previously I’ve used rsync
to synchronize the films over to the MythTV system.
Last week I made a mistake and destroyed several files.
I only noticed my mistake after I had synchronized the files, so my “backup” was gone as well.
Uups.
Therefore I switched both systems to use btrfs which allows to create snapshots.
Bareos is a backup software, which was forked from Bacula years ago. It consists of several services:
Nach einer kurzen Pause kam ich heute wieder zurück zu meinem Notebook und konnte mich nicht mehr anmelden.
Nach einigem Suchen bin ich in journalctl -u sssd
über folgende Fehlermeldung gestolpert:
[sssd[krb5_child[18654]: Disk quota exceeded
At work I need minimal Docker images.
debootstrap
is Debians default way to create chroot
environments.
By default they include all required and essential packages.
For a hardware system this is okay, but too much for a container image.
For some development work on an Univention Corporate Server 4.4, which is based on Debian Stretch, I needed a Ceph cluster based on the Jewel release. Most of the tutorials were based on newer Ceph releases (Luminous, Mimic) or were using ceph-deploy, which is not part of Debian and must be installed separately.
Therefor I did a manual installation, using the low-level tools. In contrast to Ceph Storage with UCS I do not want to use CephFS, but use Rados directly.
This is a test setup and not appropriate for production:
ext4
file system, so no partitioning, no fast journal disks, and issues with extended attributes.Q: How do you find the process listening on an UNIX domain socket?
This is some WIP. Setup GitLab in Kubernetes (k8s) test cluster using the helm chart:
Debian 10 Buster was release at the beginning of July 2019.
Debian 11 Bullseye was release at the beginning of July 2021.
Debian 12 Bookworm was release at the beginning of July 2023.
But how to make a bootable USB stick from it?
VirtIO provides Memory Ballooning: the host system can reclaim memory from virtual machines (VM) by telling them to give back part of their memory to the host system. This is achieved by inflating the memory balloon inside the VM, which reduced the memory available to other tasks inside the VM. Which memory pages are given back is the decision of the guest operating system (OS): It just tells the host OS which pages it does no longer need and will no longer access. The host OS then un-maps those pages from the guests and marks them as unavailable for the guest VM. The host system can then use them for other tasks like starting even more VMs or other processes.
If later on the VM need more free memory itself, the host can later on return pages to the guest and shrink the holes. This allows to dynamically adjust the memory available to each VM even while the VMs keep running.
Mein Notebook ist heute beim Kopieren des UCS-4.3-4 ISO-Images auf einen USB-Stick abgestürzt. Was war passiert?
Es gab bereits einen Blog-Eintrag Shell-trivia #1: set -e, aus gegebenem Anlass hier die Fortsetzung:
Debian had started to make their build reproducible: Two builds of the same source package should produce bit identical binary packages. This allows anybody to verify that nobody tempered with the build system.
Q: Was passiert durch folgende Shell-Kommandos:
mkdir ./dir
ln -s dir ./symlink
ln -s dir ./symlink
Q: Wie kann ich XML-Definition von VMs anpassen?
git-filter-branch
can be used to rewrite the history of one or more branches.
As a Debian Developer working for Univention GmbH I often have to work with Debian packages.
Here are some more examples from my daily work.
Q: Wie sieht man den Fortschritt von dd
?
Wer wie ich öfters mit der Bahn unterwegs ist weiß, dass in einigen Zügen die Bahn inzwischen WLAN anbietet: WIFI@DB. Die Bahn greift dabei auf die Technologie des Unternehmens Hotsplots zu: Nachdem man eine IP-Adresse per DHCP bekommen hat kann man noch nicht direkt los legen, sondern muss auf einer Portalseite zunächst die AGB akzeptieren. Dazu braucht man einen Browser. Das nervt mich, wenn ich das jedesmal wieder von Hand machen muss.
If you run the following shell script, it will terminate:
seq | head -n 1
But why?
Q: Wie war noch mal die Definition von inetOrgPerson im LDAP Schema?
Mit “Stream Editor” sed
hat Linux ein leistungsfähiges kleines Tool, mit dem man Texte verarbeiten kann, wo grep
und Co. an ihre Grenzen stoßen.
CPUID
is an assembler instruction to identify Intel compatible CPUs.
Calling that instruction with register EAX
set to 1
returns information about the CPU model in register EBX
.
Kennt ihr schon shellcheck?
In Skripten solltet ihr besser install
verwenden.
My company notebook (A Lenovo ThinkPad L470) sometimes crashed when I put it into the docking station: It turn back on, the external monitor turns on, but after that I only see a black screen with the mouse cursor. Today I had enough and performed the pending firmware update, which also includes the Intel CPU microcode updates.
mypy prüft statisch (d.h. zur Entwicklungszeit und nicht während der Laufzeit) Python-Code auf korrekte Datentypen. Eigentlich ist Python ja untypisiert, was schön ist, weil man nicht Variablken vorab deklarieren muss und damit jede Menge Tipparbeit spart. Andererseits führt das eben dann ggf. erst zur Laufzeit dazu, dass einem der Code um die Ohren fliegt, weil Typen eben nicht kompatibel sind.
⚠️ cgitb is deprecated since Python 3.11 and has been removed with Python 3.13!
Q: Wie installiert man die Abhängigkeiten für den Bau eines Pakets?
Viele von euch werden schon mal ein ls
auf omar in /var/univention/buildsystem2/apt/ucs_4.3-0/all/
oder einem ähnlichen Verzeichnis ausgeführt und sich gewundert haben, warum das so lange dauert.
Debian ist ein treibende Kraft für reproduzierbaren Paketbau: Ziel ist es, dass jeder ein Quellpaket erneut bauen kann und dann bei gleichen Vorbedingungen (Compiler-/Library-Versionen) exakt die selben Binärpakete enthält. Das ist wichtig für die Sicherheit, um garantieren zu können, dass weder auf dem Rechner des Entwicklers noch auf den Servern von Debian manipulierte Software den Paketbau beeinflussen.
Letzte(s) Woche(nende) war ich in Fulda auf dem Debian Secure-Boot Sprint. Ziel war es bei Debian für die nötige Infrastruktur zu sorgen, damit EFI-Binaries und Linux-Kernel-Module dort automatisch signiert werden können. Die Herausforderung für Debian besteht darin, das es dort viele Entwickler gibt, die Zugriff auf diese Infrastruktur brauchen:
Oder: Warum ucs-test
in EC2 so langsam ist – Folge 1
Wer kennt das Problem nicht: Die VM wurde über Nacht auf die Festplatte suspendiert und am nächste Morgen geht die Uhr der VM falsch.
Scan directory univention
for Python modules and generate .rst
files in directory sphinx
:
In the beginning, there was
void
.
As a C programmer you probably know strcpy()
, but hopefully strncpy()
, too.
But do you also know strlcpy()
(from BSD) and strscpy()
(from the Linux kernel)?
And do you know the suitable differences?
Calling strXcpy(dst, "text", sizeof dst)
returns … and afterwards dst
has … with
¶
the NUL-byte·
unmodifiedvariant | D < S | D = S | D > S |
---|---|---|---|
strcpy |
dest: text💥 | dest:text¶ | dest:text¶· |
strncpy |
dest: text | dest:text¶ | dest:text¶¶ |
strlcpy |
l: tex¶ | l: text¶ | l: text¶· |
strscpy |
-E2BIG:tex¶ | l: text¶ | l: text¶· |
strscpy_pad |
-E2BIG:tex¶ | l: text¶ | l: text¶¶ |
Sometimes you add a temporary APT source to /etc/apt/sources.list
, install same packages and remove the repository again.
Or you install some .deb
file directly, which you copied by hand to your environment.
RFC 2368 specified the mailto:
syntax.
It was superseded by RFC 6068, which added UTF-8 support.
It can be used to launch your email client by clicking on some URL.
Some of my notes on using FFmpeg.
Unwanted binaries like viruses should be prevented from loading. This is known as Secure-Boot. The (U)EFI firmware only loads binaries signed by the “Platform key” (PK) certificates. The PK is pre-installed by the manufacturer. Probably 9x% come with Microsoft Windows pre-installed. Therefor most PCs come with Microsoft key pre-installed. For QEMU/KVM there is “OVMF”: It is based on the EDK2 (EFI Development KIT). It is developed by the “TianoCore” community. It has not keys pre-installed.
Ich musste wieder einmal zu oft nachlesen, welche Varianten von Datei-Locking es unter Linux gibt und was die Stolperfallen sind.
I had to search man 1 find too often for printf
:
Mit iproute2
hat Linux schon lange einen Nachfolger für die althergebrachten Tools wie ifconfig
und route
.
Die gibt es zwar immer noch, aber für viele neuen Funktionen braucht man dann schon extra Tools wie bridge-utils
, vlan
, ifenslave
(für Bonding).
Der exakte Umfang hängt allerdings von der Kernel-Version und von der Paket-Version von iproute2
ab.
Kleine Denksportaufgabe für den Morgen:
Was gibt folgendes Skript aus, d.h. was wird durch das set -e
als Fehler gewertet und führt zum Abbruch des Skripts:
#!/bin/sh
set -e
! false ; echo 0
! true ; echo 1
true && true ; echo 2
true || true ; echo 3
false && true ; echo 4
false || true ; echo 5
false && false ; echo 6
true || false ; echo 7
true && false ; echo 8
false || false ; echo 9
f () { false; echo 10; }
if f; then echo 11; else echo 12; fi
Vom 15 bis 22.8.2015 fand die diesjährige Debian-Konferenz DebConf in Heidelberg statt. Ich war von Samstag bis Dienstag da und fasse nachfolgend nur die wichtigsten Dinge zusammen – wer mehr wissen möchte, kann mich gerne direkt ansprechen. Ansonsten verweise ich auch gerne auf die Videos.
Mit Bug 36044 hatten wird das Problem, das eine geöffnete TCP-Verbindung zu unserem Update-Server steckengeblieben ist und damit unsere Tests solange blockiert hat, bis wir sie von Hand abgebrochen haben.
Aus der Kategorie “Nützliche Tools” für das Schreiben von (UCS-)Tests:
Q: Wie bekommt man Zugriff auf eine 50 GiB großes Qcow2-Datei auf einem anderen KVM-Server, wenn die lokale Platte dafür zu klein ist oder man nicht bereits ist, so lange zu warten, bis die Datei komplett kopiert ist?
A: Man kann die Datei per Network-Block-Device (NBD) nur-lesbar exportieren und auf einem anderen Rechner einbinden:
Teil 2 von „Schlaflos in Oldenburg“:
from subprocess import Popen, PIPE
producer = Popen(("producer",), stdout=PIPE)
consumer = Popen(("consumer",), stdin=producer.stdout)
ret = producer.wait()
Wo ist das Problem?
Ich könnte diese Folge auch „Schlaflos in Oldenburg“ nennen, aber hier ein Beispiel, wie man es nicht macht (in Auszügen):
Wenn man das Zeichen-Encoding richtig machen will, empfiehlt es sich, intern mit Unicode zu arbeiten und bei jedem Zugriff auf das Dateisystem die Daten zwischen dem internen Unicode-Format und der externen Kodierung zu konvertieren. Leider ist Python-2 aus Kompatibilitätsgründen dazu gezwungen, sein altes kaputtes Verhalten beizubehalten. Besser wird es erst mit Python 3, wo dann alle Zeichenketten standardmäßig Unicode verwenden und man explizit sagen muß, wenn man ein Byte-Array haben möchten. Kaputt deswegen, weil:
Open Virtualization Format (OVF) ist eine Spezifikation, die es ermöglicht, Virtuelle Maschinen leicht in die eigene Virtualisierungslösung wie QEMU, Xen, VirtualBox oder VMWare zu importieren bzw. zwischen diesen auszutauschen. In der einfachsten Form besteht so eine VM aus einem Verzeichnis mit 3 Dateien:
Das devsync
-Programm aus dem toolshed ermöglicht es ja, Dateien vom lokalen System in eine VM zu synchronisieren, um darin dann den Bauvorgang anzustoßen.
Mit QEmu/KVM auf dem lokalen System geht es übrigens noch ein bisschn besser, denn per 9p (vom Betriebssystem Plan 9) kann man ein lokales Verzeichnis auch direkt innerhalb einer lokalen QEmu-VM einbinden, je nach Bedarf nur-lesend oder auch durchlässig in beide Richtungen.
Der Ein oder Andere wird es vielleicht mitbekommen haben, aber einer unserer Kunden hat Ende Januar die Gefährlichkeit eines rm -rf /
als Benutzer root erfahren (für die nicht-Techniker:
Lösche rekursiv alle Dateien und Verzeichnisse, angefangen beim Wurzelverzeichnis und ohne weiteres nachfragen).
Zum Glück hatte der Kunde ein 18h altes Backup, aber trotzdem ist viel Arbeit über den Jordan gegangen, weil unter anderem auch die ganzen virtuellen Maschinen per NFS unter /nfs/ gemounted waren… die Betonung liegt hier auf „waren“ 🙁
Wäre es an der Stelle nur ein rm
gewesen, wäre die Sache vermutlich auch noch gut ausgegangen, denn ein rm -rf /
kann man gefahrlos einfach mal so eingeben:
Wenn KVM-Instanzen das latest-ISO-Image einbinden kommt es immer wieder vor, daß nach dem Neubau der Image-Datei die VM Lesefehler meldet:
Auf der Suche nach $1 gleichen Zeichen $2 hatte ich ursprünglich folgenden Code:
ruler () { # count char
local i
for ((i=0;i<$1;i++))
do
echo -n "${2:-=}"
done
}
dpkg
behandelt alle Dateien unterhalb von /etc/
gesondert, da es sich dabei um sog. conffiles handelt:
“Änderungen daran durch den Benutzer müssen laut Debian-Policy selbst bei einem Paket-Upgarde erhalten bleiben.” Diese werden auch nicht bei einem normalen remove entfernt, sondert erst bei einem purge.
Dazu speichert dpkg
für jede Konfigurationsdatei in /var/lib/dpkg/status
die md5-Summe der Originaldatei, um geänderte Dateien zu erkennen.
(Diese lassen sich durch dpkg-query -W -f '${Conffiles}\n' "$pkg_name"
auslesen).
Leider ist das Erstellen, Zurückspielen und Löschen von Sicherungspunkte sowohl in unserer Testumgebung (und leider auch bei Kunde) mit qemu-0.14.0 extrem langsam: Standardmäßig verwendet KVM als Cache-Strategie writetrough, was dafür sorgt, das Änderungen sofort auf die Festplatte zurückgeschrieben werden, um Datenverlust bei Stromausfall vorzubeugen. Bei den Dateioperationen für Sicherungspunkte müssen an sehr vielen Stellen Änderungen gemacht werden, was dann zu der schlechten Performance führt, insbesondere wenn auch noch NFS verwendet wird.
Das Python subprocess
Modul hat so seine Tücken:
Mit Virtualisierung trifft man öfters auf mehrere Gigabyte große Image-Dateien, die von Zeit zu Zeit auch mal kopiert werden müssen.
Klassischerweise passiert das mit cp
oder dd bs=1G
.
Beide Varianten lesen die Daten häppchenweise per read()
in den Hauptspeicher, um ihn anschließend per write()
in eine neue Datei zu schreiben.
Die dd
-Varianta hat hier den Vorteil, daß man durch Angab der Blockgröße größere Datenblöcke am Stück einlesen kann, was vor allem die Anzahl der Lese-/Schreibkopfpositionierungen der Festplatte reduziert, was zu erheblichen Geschwindigkeitsvorteilen führen kann.
cp
verwendet normalerweise 32 KiB-Blöcke, shutil.copy2()
aus Python nur 16 KiB-Blöcke (und kopiert nicht alle Berechtigungen!)
Zum Testen des Univention-Updaters wird dieser oft auf einem alten UCS-System installiert und dann damit ein Update auf die aktuellste Version durchgeführt. Dabei mischt man Pakete aus dem offiziellen UCS-Depot mit neueren Paketen von omar. Um sicherzustellen, daß man nur den neueren Updater und nicht auch weitere Pakete von omar verwendet, kann man apt-Pinnging verwenden:
Bei KVM wird fast immer das Qcow2-Dateiformat für die Speicherung des Festplattenimmages verwendet.
Dieses Format belegt zunächst wenig Speicher, wächst aber bei steigender Nutzung durch das Gast-Betriebssystem bis zur angegebenen Höchstgrenze an.
Durch Sicherungspunkte kann so eine Datei aber auch deutlich größer sein als die nominal vorgegebene Größe.
Dies kann u.a. dazu führen, das im Betrieb das Dateisystem des Host-Systems voll läuft und die Qcow2-Datei nicht weiter anwachsen kann.
In diesem Fall pausieren die betroffenen KVM-Instanzen, so daß es hier nicht zu Datenverlust kommt, solange das nicht von Hand per /domain/devices/disk/driver/@error_policy="stop|ignore|enospace"
geändert wurde.
Nachdem man wieder freien Speicherplatz geschaffen hat, muß die VM per Kommandozeilentool fortgesetzt werden:
sudo virsh qemu-monitor-command "$VM" cont
.
Wenn ein Python-Prozeß zu hängen scheint und keinen Mucks mehr von sich gibt, kann gdb
noch ein Stück weiterhelfen um herauszubekommen, wo der Prozeß hängt.
Unter /usr/share/doc/python2.?/gdbinit*
gibt es verschiedene Macros, die in gdb -p "$PID"
per source /usr/share/doc/python2.?/gdbinit*
eingelesen werden können.
Anschließend liefert ein thread apply all pystack
einen Strack-Trace aller Threads.
Damit das ganze funktioniert, sollten einige Debug-Pakete installiert sein, mindestens jedoch python-dbg, libc6-dbg.
Solange man genügend Ressourcen hat und der Rechner bzw. die Festplatte nichts zu tun hat, ist es fast immer egal, welche Prozesse genau was machen. Wehe aber, wenn die Ressourcen nicht für alle gleichzeitig ausreichen und der Kampf darum beginnt, denn dann zählt nur noch jeder Prozeß für sich. Das kann dazu führen, daß der Benutzer mit 10 Prozessen eben auch die 10-fache Rechenzeit bekommt als der brave Benutzer mit nur einem Prozeß.
Weil ich es immer wieder selber nachgucken muß, wie man am besten Bibliotheken paketiert und die Abhängigkeiten zwischen den Paketen korrekt deklariert, hier zwei nützliche Links:
Nach dem Pizza-Abend-Vortrag von Jan-Christoph ist irgendwann mal das set hidden
in meine ~/.vimrc
gewandert, mit dem Dateien durch ein :q
nicht sofort geschlossen werden, sondern in den Hintergrund wandern, so daß man ggf. schnell dort weitermachen kann, wenn man die Datei dann doch nochmal öffnen und weiter bearbeiten will.
Nachteilig war das allerdings im Zusammenhang mit VCS-Plugin, weil sich nach einem VCSVimDiff
dieser Modus nicht mehr ordentlich beendet hat:
Die SVN-Datei blieb auch als Puffer geöffnet, was dazu geführt hat, das im Hintergrund diese weiterhin mit der Arbeitsdatei verglichen wurde.
Nach langer Suche habe ich dann :bdelete
entdeckt, mit dem man einen Puffer selbst bei gesetzten hidden
schließen kann.
Sönke suchte eine einfache Möglichkeit, alle veralteten Kernel von einem System zu löschen. Das sollte folgender Einzeiler erledigen:
C-Programmierer kennen es zu genüge, das im Fehlerfall solch passenden Werte wie NULL
oder -1
zurückgegeben werden.
Leider ist diese Art der Fehlerbehandlung auch in etlichen Python-Programmen gang und gebe, die meiner bescheidenen Meinung die Fehlersuche und Behandlung erschweren.