website/content/baguette/_index.md

26 KiB

+++ title = "Baguette - OS, tools and stuff"

paginate_by = 5 +++

1. Concise overview

BaguetteOS status: Work In Progress. A beta will be available circa mid-2020 for advanced users.

TODO: explications partie Custom Tools, factorisation, exemples de code et de commandes, liens vers d'autres projets.

Warning: this documentation is currently oriented toward advanced unix users.

Objectives, for simple users

BaguetteOS aims at provide a simple unix-like system, with an unified web interface.

No command-line required for simple users. let users be just users
Simplicity should not only comes from an interface, but be inherent to the whole system. If the OS is simple, there is no need to hack it.

Unified interface is better than features.
We will provide the basic features then build up. We do not want a patchwork of very different software, each of them having their own particularities.

Online services. day-to-day use
The web interface should cover online services, providing an unified experience for main usages: mails, calendar, instant messaging, personal website, file sharing, etc.

One-click management. service installs, updates, etc.
The web interface should handle basic system and network configurations, such as adding users, dhcp, DNS, backups, etc.

Well-known, reliable software. for real
BaguetteOS relies on robust and independent software. At no point the user should be forced to reinstall, a misconfiguration has to be easily fixed. Static compilation for system tools (at least): there is almost no way to get a broken system with an update (yes, almost, people are creative these days).

Hardware support. new or old, fast or slow, it doesn't matter
We provide support for RPi and other small cards: if our kernel runs on it, it has to work. Minimal hardware requirement should be around 100 MB RAM, 50 MB disk.

Documentation. simple, reliable, useful, all-in-one-place
Similar to the OpenBSD FAQ: updated, complete, concise and well-written.

Constrained devices use case. wanna try what small systems can do?
By default, we try to provide the smallest memory footprint: we do not ship manuals, nor runtime libraries when not required. Our programs will never require you to download development libraries, nor alternative package managers. The kernel is compiled with size in mind, as our choice of tools. As a result, our system can be installed quickly even on slow machines.

Objectives, for advanced users

A knowable OS. simplicity at (almost) all cost
Any interested user should be able understand the role of every part of the base system: no compromise. This means having a very small and consistent set of tools, easy to learn, easy to remember.

Basic system and network management. with the simplest tools ever
We provide a web interface that should handle basic system and network configurations, such as adding users, firewall management, dhcp, DNS, backups, etc. CLI tools are available to manage your services, they are design to be simple, consistent and reliable.

Officially supported and documented services. so you are sure to get them working
We use some services for our own personal usage, so we will provide support for them. For instance: gitea, postgresql, a building plateform and a continuous integration tool, etc.

One need, one tool. this time for real
Installing an application or a library is done by package. Other methods are not supported and the base system will never require them. We avoid to rely on pip, cpanm, or other third party package manager and dependency tree. More on that in the technical section.

Starting, stopping, or configuring a service is done by service. This program alone is used to manage services on the OS. Users should not be required to manually configure each software; instead, most of the configuration should be done upstream using templates. Users should be able to change the default configuration through command-line options. Manual configuration is the last option.

Slotting. any software can be installed on any machine at any time, no extra tooling
Slotting by default helps to install many programs, even with peculiar library version requirements. The same program can be installed in several versions without conflicts.

Objectives, for contributors

Simple to contribute to. you can focus on providing recipes for packages, we handle the tooling
We want fewer and simpler tools as possible, even for packaging applications and libraries. BaguetteOS ships a simple tool to package applications and it only requires you to create a very simple recipe for your package. It handles slotting, compiling, stripping binaries and libraries, splitting the result into different packages (-man, -lib, -doc, etc.) then authenticate them and finally recreate the index. All that, just by typing packaging app, nothing more.

meanie meanie dev

No Makefile? no problem
Your application or your library lacks a build system? Here a tool to create makefiles. It works on any language, yes, even that one.

Stable and development versions: same thing. slotting, again and again
One of the coolest aspect of slotting is: you don't need to change your system at all to be on the development version of the OS. The development of the newest version of the OS is just slotted in /usr/baguette-dev and that's it. At any point in time you can execute programs from your stable OS, or if you will, change a few environment variables and be in dev.

New OS, open to explore
BaguetteOS do not suffer from cumbersome historical decisions: no overly engineered package format, no stupidly complex patchwork of mismatch tools. BaguetteOS is easy enough to understand then even try to surpass it.

Easy to write documentation. easy to write, hopefully less procrastination
Online documentation is written in Markdown (thanks Zola), and man pages too thanks to scdoc. Every tool is shipped with a man page: no man page, no integration in base.

Inspiration

  • CRUX, alpine: simple to understand Linux systems
  • OpenBSD: security, therefore simplicity, no compromise
  • PFsense: system and (even advanced) networking administration, yet through a simple website
  • Plan9 and Inferno: everything is a file no seriously guys
  • suckless and cat-v: simplicity, code readability and re-usability
  • morpheus: static compilation for the OS, demystified

Why not use another system?

This section could be expanded.

A few reasons why any of the candidate covers it all.

  1. we want slotting
    So we could change the way we install and maintain packages.
  2. we want fast install and start-up on dumb devices
    Coreutils shrank to bare minimum, thanks to toybox. We won't require a full-feature system with several hundred megabytes of used disk-space.
  3. documentation is important, but not for all installations
    Your 42nd test install on a virtual machine doesn't need to provide manual for CLI tools you won't use since you do everything through the web interface. Software and its documentation will be split: manual pages won't be provided by default.
  4. we want automatic tests, and to allow people to test our system
    We want easy chroot installs, on any system.
  5. we want to run on tiny ARM boxes, old laptops, top-notch servers
    So we need to run on any available kernel.
  6. we want to control software distribution releases
    We don't accept to follow updates from an upstream OS that could break our system at any time.

Now, let's take a look at each candidate.

OpenBSD. we will get there quick, but focus on Linux a bit before
We definitively want to use OpenBSD, currently we just focused on Linux for hardware compatibility reasons (and out of habits) but it's not set in stone. We love OpenBSD big time, some of us use it daily. We aim at providing rootfs for running our system under an OpenBSD kernel and environment.
(also, snapshots could be great, guys)

PFsense. network focused
Way too focused on networking. Great system, does the job very well, but won't fit our objectives.

CRUX and Alpine. great source of inspiration
We do use the CRUX's rc script, and as Alpine it is a source of inspiration for package recipes. However, since we have to change all packages to get slotting, the service manager to have tokenized services, the packaging software to get declarative recipes (...), why even bother use those systems?

GUIX and coe. not simple enough
This approach of package management is interesting, having to learn a language to make recipes isn't. And that sums a lot about this technology. It's great to have, not to put everywhere. Every part of BaguetteOS is simple to understand, GUIX is not simple enough. But keep it up guys, it's still awesome.

Plan9, Inferno, morpheus, etc. kinda abandoned systems
That's it.

2. Technical choices

Base system

Linux kernel, but we are lurking on the OpenBSD one.
Linux is compatible with most hardware and software, it is fast and we can easily compile a custom version to remove most of the bloat for server usage. Still, we don't want to rely on Linux-specific components. At some point, our system will be kernel-agnostic and will be able to run on any BSD as well. OpenBSD has pledge and unveil syscalls, which is an elegant way to provide a guarantee on the software behavior.

Musl. reasonable libc for Linux
It has a reasonable amount of features, it is efficient, provides reasonable binary sizes and static compilation. Musl is simple, reliable and remove all glibc-specific functions. Others can be added easily, which is useful for compatibility and comparisons, through slotting.

Bootable system and rootfs available.
A bootable system to install in virtual machines or bare metal, a rootfs to use BaguetteOS from any other OS, including non-Linux ones.

SysV-style init + CRUX-like /etc/{rc,mdev.conf,...}. easy to read, easy to adapt
The init could come from toybox or another minimalist project. The rc script from CRUX is simple to understand and to adapt to any requirement, so we used it. We also added some other scripts, like for profile so we can easily manage slotting. No systemd BS.

Toybox. the megabyte coreutils
Toybox combines common unix command line utilities together into a single BSD-licensed executable. It is designed to be simple even to read, and is standards-compliant. For the base system, that's all we need.

ksh and zsh. the first for scripts and root, the other for users
Ksh is a very stable and reliable shell from AT&T, trusted by the paranoid people of OpenBSD. That's a safe choice for a base system and the root account. On the other hand, we do use zsh daily, as for many users, so we may use it for development or build scripts but not in base.

Service for service management tokenized service description, templating and dumb cli tools for the win
See custom tools.

Package for package management simple, efficient, dead simple code
See custom tools.

OpenSSH. as we all know and love
This is required for almost all usages, and for debug. Let's try not to shoot ourselves in the foot.

That's all you need for starters. Web administrative interface will be added to the base when ready.

Development, build tools, contribution

Default building tools every tool needed to bootstrap
Clang (+ LLVM) is the default C (and C++) compiler. Libarchive is required for tarballs, packages, webhooks from packaging, and both bsdcpio and bsdtar (sane implementations of cpio and tar). [Auto-tools][autotools] are also required (for SysV init and libarchive). m4 and gnu-make are required for compatibility reasons.

Documentation.
A full hand-book like the OpenBSD FAQ. Our software man-pages are written with scdoc so anyone can contribute.

Packaging for packaging software and libraries. dead simple, intuitive
See custom tools.

Crystal language for system tools. syntax and productivity of Ruby, the speed of C
It is as simple to learn as a dynamic (oriented object) language, while at the same time being almost as fast as C. Technically, Crystal is strongly typed which catches errors at compile-time, but with type inference so it is not cumbersome to use. Applications are compiled in a simple binary, easy to deploy. There is a good documentation, we used it for long enough to tell. Technical choices are reasonable and documented. Finally, Crystal has a large library with all we need for our system components.

There is not much of a drawback here. Yes, this is a language you have to learn to work with us on a couple of projects (the web interface back-end, the service manager, the package manager and packaging) but it increases our productivity like crazy. We heard about nim and a ton of other languages, but this is the one which reach the sweet spot between these parameters:

  • productivity (the package manager was mostly done in a few days, and is just a few hundred lines long)
  • easy learning (a developer with basic notions of oriented-object can read our code, no black magic here)
  • good documentation
  • reasonably deployable (no host dependencies)
  • execution speed

Slotting. custom file system hierarchy
Our FS is not FHS-compliant, partially because of the origin-based slotting. There is a strict separation between core system and third party software.
More information on slotting.

  • /usr/baguette for core system programs
  • /usr/bad for non slot-able software
  • /usr/third-party for other software

3. BaguetteOS: custom tools

All our tools are designed to be simple to use, to understand, to read. Feel free to provide a feedback.

TODO: spec files, the file format used in package, packaging and service.

name: hello
version: 2.10
release: 2
sources: https://ftp.gnu.org/gnu/hello/hello-%{version}.tar.gz

dependencies:
  - gettext

build-dependencies:
  - make

options:
  - configure: --disable-nls

@watch
	curl 'https://ftp.gnu.org/gnu/hello/' -o- 2>/dev/null |
	sed -n "/hello-.*\.tar\.gz/{s/\.tar\.gz.*//;s/.*hello-//;p}" |
	tail -1

TODO: explains why it's different / better than other package managers.

Package: our package manager.
Package covers the basics: install, remove, search and provide informations about a package, and it creates rootfs. Package knows the minimal set of binaries and configuration required to build the target, so it only installs the minimal environment to perform compilation.

Package provides slotting by default: no need for custom environments for each software.

Packages format is a simple tar archive containing a meta.spec file describing all meta-data about the package (hash, manifest, etc.) and files.tar.xz with the files to install. The database format contains world, installed, [package-name]/[slot]/manifest and [package-name]/[slot]/meta.spec.

Package's configuration is a list of repositories, authorized package signing keys and packaging variables (cflags, makeflags, and so on).


Packaging: to create packages.
Packaging uses simple, declarative recipe files, here some examples: hello, dhcpcd, alsa-utils. The only required parameters are name and sources.

Packaging creates build environments to test packages before validation. It works as follow:

  1. creation of a /tmp/packaging/build-UUID/ directory
  2. sources are downloaded, extracted then compiled
    Recipes and packaging host configuration may add parameters to it: adding steps before compilation, changing configure arguments, etc. The package is compiled for a specific slot, by default /usr/baguette.
  3. compiled applications and libraries are put in /tmp/packaging/build-UUID/root which is used to create the final package

Packaging uses package to create low-cost build environments since we hardlink binaries into the building rootfs, which is inspired by the proot tool on OpenBSD.

TODO. Packaging configuration is simple.

TODO. Packaging recipes.


Factorisation.

Service: service management. not just kill or start/stop/status wrapper
Service management often comes with:

  • default configuration files, users should learn how to configure them and do it manually
  • a single possible instance, otherwise the configuration has to be heavily changed
  • root-only management, simple users rarely run their own services (except on systemd, kuddos for once)
  • no domain management

These shortcomings imply manual configuration, scripting to manage databases and users, specific tooling for each database and service: this is heavy machinery. Simple users:

  1. should be only required to provide absolute necessary information for their services
  2. should be able to run as many services they want
  3. shouldn't have to learn configuration syntax for their services
  4. shouldn't be afraid of updates

Here are a few functionalities service brings.

  1. domain-wise service configuration
    Example: service add wordpress domain=example.com

  2. templates configuration files are generated by templates and user data
    When we want a software, for instance a blog, we want to provide the minimum informations it requires to work and that's it. When service is invoked to start a service, it verifies if a configuration file is installed or create it. Users shouldn't need to manually change the configuration. Syntax may change at any time without breaking a single service, since the configuration will smoothly be regenerated with useful information at start-up.

  3. environments
    Each service can be installed in a specific environment (read: a custom rootfs). Example: service add wordpress example.com testing-env

  4. unified way to configure the system
    It alleviates the need for manual configuration. For example, adding a Wordpress service will automatically change the nginx configuration, create a new database and a new user in mariadb for this specific service. If several nginx are required, ports will be registered and automatically managed for each instance, no need for user input.
    Behind the scene, it's a simple token system with configuration templating!
    No heavy machinery here, and we'll keep it that way.


Better introduction.

LibIPC: an IPC communication library nothing new, yet it still feels fresh

  1. Applications should talk to each other
  2. We need services, not libraries
    Therefore, languages are irrelevant: you can use any library in any language.

LibIPC is currently used for the administration dashboard, the web interface for the services, [for a kanban][todod] and several other tools we use for collaboration. It provides a way to communicate between clients and services using simple unix sockets behind the scene.

Explain remote communications. Remote remote communications are transparent. - clients and services do not need remote communication - any client can join remote services via any communication protocol - any service is implicitly accessible from anywhere, anyhow

C library with Crystal bindings (other languages coming soon)


require "ipc.cr"

server = IPC::Service.new "MyService"
server.loop do |message|
    # ...
end

TODO: show that's easy to write even in plain C.

TODO: performances are crazy, we have to tell the world.


TODO. Build.zsh: makefile creation. for mere mortals
Build.zsh creates a makefile from a simple declarative configuration file. It can replace most build systems.


TODO. tap-aggregator: quality assurance & test results aggregation


TODO: better explanation. Webhooksd: verify recipes.
Webhooksd provides an automatic verification of the recipes, based on new application or library version. Paired with a build system, new recipes received in the repository create packages for a couple of architectures (x86_64, ARM, others will follow).

Still in discussion

For the simple users, we want to provide an unified web interface to manage the system and online services. We currently use Crystal to work on service back-ends for a variety of projects, we are satisfied on a technical level and we are productive, it is highly probable we continue using it. The front-end is still in discussion: we currently use livescript and it is way more usable than plain JS, but it is painful to debug.

So, we need a language for both administration dashboard and online services, here some examples we find interesting for the job:

  • Purescript
    • haskell-like syntax, with a smaller set of notions
    • strongly typed, with type inference
    • good documentation
    • useful compilation errors
    • no runtime error
  • Elm
    • as Purescript but with way fewer documentation (but reading the code is sometimes enough here)
    • less generic code (functions such as fold and map have hardcoded type), which feels a bit hacky
    • still very young
  • WASM
    • seems to be a very young tech, with no real good language or documentation
    • Zig has wasm as a Tier 1 support, we should investigate

4. Slotting: providing software the right way

The usual way to provide software is to maintain a version of a software or a library, package it into a distribution, then provide it as the OS version of the software. In the long run, software and libraries change, which is no big deal since maintainers verify the consistency of the different versions provided by the OS.

TODO

Problem: what happens when two programs need a different version of a library?
Problem: what happens when two libraries are compatible but you want both on your system (see libressl and openssl)?
Problem: what happens when you want to provide a very long term support for your users (see companies running decade-old databases)?

BaguetteOS has a simple and safe way to let users and maintainers provide packages: slotting. Official OS packages are installed under /usr/baguette/, for non-essential programs. Here, the slot is baguette. Any package outside the official ones are in another named slot.

TODO

This in nothing new, however not often used, and still maybe the best way to handle the problem.

BaguetteOS file system hierarchy

  • usual directories under root: bin, sbin, lib, boot, dev, proc, sys, home, mnt, root, run, tmp
  • /etc/rc with services and environments for running service instances
  • /etc/templates for local service configuration templates
  • /var/cache
  • under /srv/"env-name" (see service), these subdirs when required: /etc, /data, /cache, /run
  • under /usr
    • /local: things that are installed by the local system administrator without using packages
    • /baguette: things provided by the system that are not necessary for it to run (and boot, and restart, and do system things)
    • /"repo": /lib, /bin, /share, /man, /include (/libexec but we try to avoid it whenever possible.)
    • /bad: things that cannot be properly installed or slotted somewhere else

Roadmap

TODO

We currently aim at providing a rootfs with our tools, when we will have enough spare time to contribute.