website/content/baguette/index.md

979 lines
45 KiB
Markdown
Raw Normal View History

2020-04-23 17:51:38 +02:00
+++
title = "Baguette - OS, tools and stuff"
paginate_by = 5
+++
- [Overview](#overview)
- [Technical choices](#technical-choices)
- [Custom tools](#custom-tools)
- [Slotting](#slotting)
- [Roadmap](#roadmap)
<a name="overview"></a>
# 1. Concise overview
BaguetteOS status: Work In Progress.
2020-04-25 04:45:44 +02:00
A beta will be available circa mid-2020 for advanced users.
End of the year for simple users.
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
<red>Warning:</red> this documentation is currently mostly oriented toward advanced unix users.
We provide insights on system administration, expose our ideas and point of view.
Documentation for simple users will be split in another page, soon.
2020-04-23 17:51:38 +02:00
## 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*<br />
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.**<br />
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*<br />
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.*<br />
The web interface should handle basic system and network configurations, such as adding users, dhcp, DNS, backups, etc.
**Well-known, reliable software.** *for real*<br />
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*<br />
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*<br />
Similar to the OpenBSD FAQ: updated, complete, concise and well-written.
**Constrained devices use case.** *wanna try what small systems can do?*<br />
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*<br />
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*<br />
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*<br />
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*<br />
Installing an application or a library is done by [package][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](#technical-choices).
Starting, stopping, or configuring a service is done by [service][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*<br />
[Slotting](#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*<br />
We want fewer and simpler tools as possible, even for packaging applications and libraries.
2020-04-25 04:45:44 +02:00
BaguetteOS ships [a simple tool to package applications](#packaging) and it only requires you to create a very simple recipe for your package.
2020-04-23 17:51:38 +02:00
It handles [slotting](#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.
<img src="/meanie-makefile.png" alt="meanie meanie dev" class="meanie-img" />
**No Makefile?** *no problem*<br />
2020-04-25 04:45:44 +02:00
Your application or your library lacks a build system? Here a [tool to create makefiles](#build.zsh).
2020-04-23 17:51:38 +02:00
It works on any language, yes, even that one.
**Stable and development versions: same thing.** *slotting, again and again*<br />
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.
2020-04-25 04:45:44 +02:00
**New OS, open to explore** *we are open to new ideas*<br />
2020-04-23 17:51:38 +02:00
BaguetteOS do not suffer from cumbersome historical decisions: no overly engineered package format, no stupidly complex patchwork of mismatch tools.
**Easy to write documentation.** *easy to write, hopefully less procrastination*<br />
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][crux], [alpine][alpine]: simple to understand Linux systems
- [OpenBSD][openbsd]: security, therefore simplicity, no compromise
- [PFsense][pfsense]: system and (even advanced) networking administration, yet through a simple website
- [Plan9][plan9] and [Inferno][inferno]: everything is a file *no seriously guys*
- [suckless][suckless] and [cat-v][cat-v]: simplicity, code readability and re-usability
- [morpheus][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.**<br />
1. **we want slotting**<br />
So we could change the way we install and maintain packages.
2. **we want fast install and start-up on dumb devices**<br />
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**<br />
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**<br />
We want easy chroot installs, on any system.
5. **we want to run on tiny ARM boxes, old laptops, top-notch servers**<br />
So we need to run on any available kernel.
6. **we want to control software distribution releases**<br />
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* <br />
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.<br />
*(also, snapshots could be great, guys)*
**PFsense.** *network focused* <br />
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* <br />
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*<br />
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* <br />
That's it.
<a name="technical-choices"></a>
# 2. Technical choices
## Base system
**Linux kernel**, but we are lurking on the OpenBSD one.<br />
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*<br />
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](#slotting).
**Bootable system and rootfs available.**<br />
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,...}][baguette-rc]**. *easy to read, easy to adapt*<br />
The init could come from toybox or another minimalist project.
The [rc script from CRUX][cruxinit] is simple to understand and to adapt to any requirement, so we used it.
We also added some other scripts, like [for profile][baguette-profile] so we can easily manage slotting.
No systemd BS.
**Toybox.** *the megabyte coreutils*<br />
[Toybox][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*<br />
[Ksh][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][zsh] daily, as for many users, so we may use it for development or build scripts but not in base.
**[Service][service] for service management** *tokenized service description, templating and dumb cli tools for the win* <br />
[See custom tools.](#custom-tools)
**[Package][package] for package management** *simple, efficient, dead simple code* <br />
[See custom tools.](#custom-tools)
**OpenSSH.** *as we all know and love*<br />
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*<br />
Clang (+ LLVM) is the default C (and C++) compiler.
[Libarchive][libarchive] is required for tarballs, packages, webhooks from `packaging`, and both [bsdcpio][bsdcpio] and [bsdtar][bsdtar] (sane implementations of `cpio` and `tar`).
[Auto-tools][autotools] are also required (for SysV init and libarchive).
[m4][m4] and [gnu-make][gmake] are required for compatibility reasons.
**Documentation.**<br />
A full hand-book like the OpenBSD FAQ.
Our software man-pages are written with `scdoc` so anyone can contribute.
**[Packaging][packaging] for packaging software and libraries.** *dead simple, intuitive*<br />
[See custom tools.](#custom-tools)
2020-04-25 04:45:44 +02:00
**Slotting.** *custom file system hierarchy*<br />
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.<br />
[More information on slotting.](#slotting)
- `/usr/baguette` for core system programs
- `/usr/bad` for non slot-able software
- `/usr/third-party` for other software
## Languages
We are reluctant to add new languages to the base system.
We will limit the number of languages required for a system bootstrap.
For now, bootstrapping requires: `C`, `perl`, `m4`, `python` (for stupid reasons).
However, we think that we can overcome C limitations, explore new possibilities.
Now, more than ever, we have better alternatives for all non kernel-related tooling.
That being said: we do not want dynamic languages.
We need:
- simple, small and efficient binaries
- less possible dependencies (not to download half `cpan` or `pypi` for any freaking software)
2020-04-23 17:51:38 +02:00
**Crystal language for system tools.** *syntax and productivity of Ruby, the speed of C*<br />
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.
2020-04-25 04:45:44 +02:00
Yes, this is a language you have to learn to work with us on a couple of projects but you can learn it in about a few days to a week and it increases our productivity like crazy.
We heard about `nim` and a ton of other languages, lot of them are great candidates, but **choices needed to be made**.
This is the one reaching the sweet spot between these parameters:
2020-04-23 17:51:38 +02:00
- productivity (the package manager was mostly done in a few days, [and is just a few hundred lines long][package])
- 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
2020-04-25 04:45:44 +02:00
We are also looking at [Zig][zig] for low-level stuff. Wait & see.
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
## naming convention
```sh
name = application name
version = application version
release = recipe version
$name-$version-r$release.pkg
```
2020-04-23 17:51:38 +02:00
<a name="custom-tools"></a>
2020-04-25 04:45:44 +02:00
<a name="top"></a>
2020-04-23 17:51:38 +02:00
# 3. BaguetteOS: custom tools
2020-04-25 04:45:44 +02:00
**Simple ideas, simple implementations.**<br />
Keep reminding to yourself while reading that our tools are implemented within just a few hundred lines of code (up to 1500 lines for `service` and `libipc`).<br />
Also, they can easily run on other systems: nothing here is OS specific.
[Feel free to provide a feedback.](#contact)
Here a few pointers:
- [spec format](#spec-format)
- [package](#package)
- [packaging](#packaging)
- [service](#service)
- [… and a few other tools](#other-tools)
2020-04-23 17:51:38 +02:00
---
2020-04-25 04:45:44 +02:00
### Main BaguetteOS tools
<a name="spec-format"></a>
**Spec files.** *our declarative format*<br />
Before presenting our tools, here a file format named `spec` that we tend to use when relevant.
It is *declarative*: we tend not to tell instructions how to do things (copy this file here, download this, etc.) but to describe something (url of the project is `https://example.com/xxx`).
The `spec format` is only composed of variables, lists, code block and named sections.
Here a quick example.
2020-04-23 17:51:38 +02:00
```yaml
# This is a comment
2020-04-23 17:51:38 +02:00
# This is a simple variable instanciation
variable: value
2020-04-23 17:51:38 +02:00
# This is a inlined list
list: a, b , c
2020-04-23 17:51:38 +02:00
# This is a multiline list
list:
- a
- b
- c
```
This looks a lot like YAML, but now we add `code block` to it: because sometimes we <u>do</u> want to tell instructions.
```yaml
# We have the URL of the tarballs for a software
software-url: 'https://example.com/my-software/'
2020-04-23 17:51:38 +02:00
# ... and we want to get its last version number
# "@watch" is a block, the name "watch" has a meaning in the application reading the file
2020-04-23 17:51:38 +02:00
@watch
# the following is simple shell scripting
curl %{software-url} -o- 2>/dev/null | \
sed "s/_my-software.tar.gz//" | \
2020-04-23 17:51:38 +02:00
tail -1
```
Sometimes, we want to refer to a file (or directory) and add metadata to it: here `named sections`.
```yaml
# as for "@watch", "%configuration" has a meaning in the application reading the file
# this time, the block has an arbitrary name
%configuration postgresql.conf
# within a named section, we find simple declarations as outside the block
name: database configuration
creation-command: my-script.sh -a -b -c
```
Next, the usage in practice: [packaging](#packaging), [service](#service).
2020-04-25 04:45:44 +02:00
[Come back to top](#top)
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
---
2020-04-23 17:51:38 +02:00
<a name="package"></a>
2020-04-23 17:51:38 +02:00
**[Package][package]: our package manager.**<br />
`Package` covers the basics: install, remove, search and provide informations about a package.
`Package` can create minimal rootfs, to bootstrap BaguetteOS on another system or to create test environments for example.
2020-04-23 17:51:38 +02:00
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).
Finally, `Package` can easily be expanded, as it only relies on a few hundred lines of Crystal code.
2020-04-25 04:45:44 +02:00
[Come back to top](#top)
2020-04-23 17:51:38 +02:00
---
<a name="packaging"></a>
**[Packaging][packaging]: creates packages.**<br />
Any OS needs a way to create packages to share software, either by sharing sources that need to be compiled or by sharing pre-compiled binaries.
As BaguetteOS is design to provide quickly usable systems, we choose to provide binaries.
`Packaging` uses simple, declarative recipe files with the `spec format` [as we saw earlier](#spec-format).
`Packaging` has a few advantages compared to most used packaging tools:
2020-04-25 04:45:44 +02:00
- **declarative recipes abstract OS specifics**<br />
The same recipe may work for many **native packaging systems** (many OSs), given that packagers provide the right target running dependencies.
2020-04-25 04:45:44 +02:00
This only requires to provide a back-end for the target package manager.
- **auto-split in different packages**<br />
We need to separate binaries, libraries and documentation in different packages, so we can only install what's needed.
Slow and testing systems only require strict minimum.
- **auto-strip of binaries and libraries**<br />
By default, a running system does not require debug symbols in its binaries.
- **recipe readability is great**<br />
A few variable declarations are better than a dozen lines of code.
2020-04-25 04:45:44 +02:00
- **trivial shell script patterns become automated**<br />
`Autotools` and `cmake` build systems are detected; packagers should only provide specific parameters for each project.
2020-04-25 04:45:44 +02:00
- **tooling may evolve, very few recipes will be require to change**<br />
Everybody wants to change its build system?
*(Besides possibly broken tools and possible workarounds,)* this is not a problem for the recipe, just `packaging`.
2020-04-25 04:45:44 +02:00
- **it creates hash'ed and signed packages by default**<br />
You need your own set of cryptographic keys, which is created at first use.
2020-04-25 04:45:44 +02:00
- **it creates repositories (automatic at first compilation), helping people maintaining their own set of tools**<br />
Change the first `prefix` in your [packaging configuration](#packaging-host-config), compile your first package and you have your repository.
That is that simple.
<img src="/shell-scripting-is-lava.png" alt="shell script is lava" />
<a name="packaging-build-env"></a>
**`Packaging` build environments**<br />
`Packages` 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<br />
Recipes and [`packaging` host configuration](#packaging-host-config) 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][proot] tool on OpenBSD.
In this case, `package` only installs the minimal set of binaries required by the package to build.
Besides the target application, a building environment size is <u>only a few kilobytes</u>.
<a name="packaging-host-config"></a>
**`Packaging` configuration**. *common configuration for your packages*<br />
`Packaging` may be configured globally for your system with the file `/etc/packaging.conf` which contains the following:
```YAML
# Configuration file for `packaging`
# where to send built packages
packages-directory: /usr/local/pkg/
# where to download sources
sources-directory: /usr/local/src/
# prefixes for `packaging` running environment and child processes
prefixes:
# the first prefix is the default slot used for building application
- /usr/baguette/
- /
# list of environment variables we want to have when building
environment:
# you may choose another compiler, provide some CFLAGS, etc.
- CC: clang
- CFLAGS: -Os -Wall
# next three have special meaning
# to provide parameters to the `./configure` script when building
- configure: --disable-nls --without-gettext
# to provide parameters to the `make` command
- make:
# to provide parameters to the final `make install` command
- make install:
2020-04-25 04:45:44 +02:00
# wanna build for another system? not a problem, just add the back-end (we currently have `apk` and `package`)
package-manager: package
```
That's it. You know all about `packaging` configuration.
These parameters may be override by recipes.
<a name="recipes"></a>
**`Packaging` recipes.** *we need to create packages*<br />
A recipe is the way to reproduce something; here we want to create a package, the recipe should provide all data necessary to be able to reproduce the package.
This means at least having a name for the software and a version (they appear in the package name) and sources (software code).
Let's take an example.
2020-04-23 17:51:38 +02:00
```yaml
# GNU Hello program
name: hello # software name
version: 2.10 # software version
release: 2 # recipe release: incremented when the recipe change for the current version of the software
# the description will appear in the package information we can retrieve with `package`
description: "This is the GNU Hello program."
# sources may be multiple: you may want to add arbitrary files along the tarball
sources: https://ftp.gnu.org/gnu/hello/hello-%{version}.tar.gz
# we provide running dependencies: the program needs these to `run`
dependencies:
- gettext
# we provide build dependencies: the program needs these to `be compiled` for the package
# no need to require these dependencies for a simple user installing the program
build-dependencies:
- make
# if we want to add or override compilation options
options:
- configure: --disable-nls
# feels like déjà vu, right?
# "watch" code block helps to check if the recipe covers the last software version
@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
```
This was [a real example][recipe-hello], and not the simplest one.
Most of our recipes currently look like this:
2020-04-23 17:51:38 +02:00
```YAML
name: dhcpcd
version: 8.0.3
sources: https://roy.marples.name/downloads/dhcpcd/dhcpcd-%{version}.tar.xz
```
That's it.
Yes, we can add a few meta-data, but this is a working recipe.
Configuration, compilation and packaging are done without providing anything else.
The only required parameters are `name`, `sources` and `version`.
<a name="packaging-manual-operations"></a>
Sometimes, developers are assholes and force you to fix their build system.
When manual operations <u>really are required</u>, you can use `@configure`, `@build` and `@install` code blocks.
Let's see an example with a special snowflake… like `perl`.
```YAML
# in our example, we want to configure the build
@configure
# we set some script execution parameters: exit at any error, print everything you do
set -e -x
# we currently are in `/tmp/packaging/build-UUID/`
# now we enter the directory created by the tarball extraction, where the build occurs
cd perl-%{version} # we can interpolate variables with this: %{}
# Perl needs a few environment variables for configuration
BUILD_ZLIB=0
BUILD_BZIP2=0
BZIP2_LIB=/usr/lib
BZIP2_INCLUDE=/usr/include
export BUILD_ZLIB BUILD_BZIP2 BZIP2_LIB BZIP2_INCLUDE
# now we can launch the `configure` script…
# … but wait kids, that's not `configure`, that is `Configure` (see the capitalized C?)
# this is a totally different and very special script, but you should love it anyway
./Configure -des -Dcccdlflags='-fPIC' \
-Dcccdlflags='-fPIC' \
-Dccdlflags='-rdynamic' \
# ... some long and uninteresting list of very specific parameters because we are Perl, we are historic and stuff
```
2020-04-23 17:51:38 +02:00
Now you know how to deal with `@configure`, `@build` and `@install`: these are code blocks allowing you to fix this kind of problems.
Non standard build operations happen from time to time, and code blocks help you overcome this.
When a lot of packages have the same workarounds, we think about detection and integration into `packaging`, so we can keep only specifics into recipes.
2020-04-23 17:51:38 +02:00
If you want to investigate a bit more, you can check [our recipe repository][recipes].
Feel free to improve these recipes with meta-data, `@watch` code blocks… contributions are welcome.
2020-04-23 17:51:38 +02:00
<a name="packaging-future"></a>
**Future of `packaging`.** *let's be even more declarative*<br />
As we saw, `packaging` allows maintainers to create very simple and **readable** recipes.
Sometimes we have to confront ourselves to poorly designed build systems, but we can hack a bit.
In the future, manual operations should be reduced even more:
- by adding a few other parameters to the environment<br />
This imply to check for patterns in the recipes and to provide workarounds.
- by adding new code blocks *before* the `configuration`, `build` and `install` steps<br />
This would allow performing a few hacks in the directory (a quick `sed` in a file for instance) and still keeping automatic operations: the best of the two worlds.
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
Another possible addition to `packaging` could be to take cross-OS recipes as first-class citizen.
It was part of the design process of spec files: `named sections` can be used to discriminate information based on the target OS.
An example:
```YAML
%OS Ubuntu-20.04
dependencies: libxxx
%OS Debian-12
dependencies: lib-with-specific-naming-standard-for-reasons
```
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
This way, bootstrapping an application and providing it to any system <u>with their own tools</u> could be easy.
It's actually what we did during the Baguette's bootstrap.
Providing universal recipes could even become a game for patient system administrators.
[Come back to top](#top)
---
2020-04-23 17:51:38 +02:00
<a name="service"></a>
**[Service][service]: service management.** *not just `kill` or start/stop/status wrapper*<br />
Service management often comes with:
- default configuration files, users should learn how to configure them and do it manually
2020-04-25 04:45:44 +02:00
- default user and group, so two instances may have security-involved issues
2020-04-23 17:51:38 +02:00
- 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.
2020-04-25 04:45:44 +02:00
To overcome drawbacks of having simplistic tools, sys-admins developed all kind of monstrous architectures.
- **LXC** *chroot + network + software limits*
- **Qemu + KVM, Xen** *let's add software mimicking hardware's complexity to the mix, telling everyone it's for security and simplicity*
- **docker** *I don't know how to do simple applications nor packages, so I ship my whole dev environment*<br />
Note: we have to admit, packaging on most OS is painful for absolute no good reason.
- **Chef and Puppet** *the 500 MB running Ruby's code on our virtual machines just to check for new configuration is okay, memory is cheap right?*<br />
We talk about the importance of security from time to time, but running a software designed by people telling [it's okay not to free memory][ruby-memory-bp] is far from being wise.
- **Ansible** *templating your applications… from another machine*<br />
As Chef and Puppet, ansible provides templating for applications, this time configuration propagation is **way** simpler since it uses well-known, trusted and loved ssh.
Still, templating is done for remote machines, as it is intended for server deployments: this is **a sys-admin tool**.
The introduction page already talks about `cloud provisionning` and `intra-service orchestration` on the first line, telling that you really need to setup SSH keys, etc.
As for many tools in IT: this is not for simple users.
2020-04-23 17:51:38 +02:00
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
2020-04-25 04:45:44 +02:00
5. ... and should have BACKUPS! Where are they? We should have that **by default** on our systems over 20 years ago.
And advanced users should have an uncomplicated CLI tool to do that.
**Let's take an example with `service`** *better than a thousand words*
```sh
# We want a wordpress service, proxied by a nginx and using postgresql as DBMS
# 1. we add an nginx
$ service add nginx
```
```sh
# 2. we add the database
$ service add postgresql
```
```sh
# 3. we add the wordpress
# by default, it uses available http proxy and database, but let's be "verbose"
$ service add wordpress domain=example.com http=nginx database=postgresql
```
```sh
# 4. we start the wordpress
$ service start wordpress
```
A bit of explanation:
1. first, we add `nginx` to the list of service we want on our system
2. same thing with `postgresql`
3. then we add `wordpress` and we pass parameters to the service configuration: `domain`, `http` and `database`<br />
`domain` for the domain name, `http` for the HTTP proxy and then the `database` back-end.
Up to this point, nothing even started.
4. Finally, we start the service.<br />
Since `service` knows the dependence graph, it starts other services before wordpress (which actually doesn't have any binary to run *per se*).
The configuration of a service is made when `service` starts it.
In this case:
1. `nginx` is started as a proxy for `example.com`
2. `postgresql` is started, its internal directories and files are created, then an user, a database and a password for `wordpress` are created
3. a directory is created in `/srv/root/wordpress/` and wordpress files are copied into it, then its configuration is generated
Stopping a service also stops its dependency, if they aren't required elsewhere (or that we explicitely said to keep them running).
2020-04-23 17:51:38 +02:00
Here are a few functionalities `service` brings.
2020-04-25 04:45:44 +02:00
1. **uncomplicated domain-wise service configuration**
2020-04-23 17:51:38 +02:00
2. **templates** *configuration files are generated by templates and user data*<br />
When we want a software, for instance a blog, we want to provide the minimum informations it requires to work and that's it.
2020-04-25 04:45:44 +02:00
When `service` starts a service, it verifies if its configuration file is installed and up-to-date, or create it.
2020-04-23 17:51:38 +02:00
Users shouldn't need to manually change the configuration.
<u>Syntax may change at any time without breaking a single service</u>, since the configuration will smoothly be regenerated with useful information at start-up.
3. **environments**<br />
2020-04-25 04:45:44 +02:00
Each service can be installed in a specific environment (read: a custom rootfs, a virtual machine, etc.).
4. **automatic user and group creation**<br />
Each service needs to be separated from other users on the system, for security reasons.
Let's make it the default.
5. **tokens** *service a needs b, b needs c, when a starts, b and c start and are configured*<br />
`service` knows the relation between services, and use it to configure them through the templates.
*everything is smoother now*
6. **automatic backup solution**<br />
Since we know each running database, service configuration and data directories, we can backup everything once a backup server has been configured.
Of course, we can add a lot of parameters to have a fine-grained backup solution.
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
```sh
# not currently done, but will look like this
$ backup add ssh:user@example.com:/srv/backup
```
7. **unified way to configure the system** *best user experience possible*<br />
2020-04-23 17:51:38 +02:00
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.<br />
Behind the scene, it's a simple token system with configuration templating!<br />
2020-04-25 04:45:44 +02:00
<u>No heavy machinery here, and we'll keep it that way.</u>
8. **... and understandable tooling output** *for god's sake!*<br />
```sh
$ sudo service show my-awesome-gitea-instance
Name: my-awesome-gitea-instance
Type: gitea
Environment: root (prefix)
Consumes:
- postgresql root/postgresql
- http root/nginx
Ports:
- http: 49155
```
**`Service`: a service example.**<br />
A service configuration has two parts: the service description and its configuration file template(s).
Let's use `gitea` as example, the `git` web server handling [our repositories][baguette-gitea].
```YAML
# `gitea.spec`
# The actual command to run to start the service
command: gitea -C . -w . -c gitea.cfg
# what tokens the service needs, see that http is optional
consumes: database, http?
# does the service requires a domain name to be configured?
# this name may be used in the service configuration, or its (forward|backward) dependencies
requires-domain: true
# the service requires a simgle port to be open
# by default, 80
ports: http
# `%configuration` indicates the name of the configuration template
%configuration gitea.cfg
```
*We **currently** uses a bit more configuration for the database, but we will get there at some point.*
Now, a quick look at its configuration template. *we'll skip most, don't worry*<br />
Templating is done with `Jinja2` templates.
<red>TODO: explain a bit more this example</red>
```YAML
# This is my template comment
[database]
DB_TYPE = postgres
HOST = 127.0.0.1:{{ providers.postgresql.ports.postgresql }}
NAME = {{ service.id | replace("/", "_") }}_db
USER = {{ service.id | replace("/", "_") }}
PASSWD = {{ random_password( service.id ) }}
[repository]
ROOT = {{ service.root }}/repositories
[server]
SSH_DOMAIN = {{ service.domain }}
DOMAIN = {{ service.domain }}
HTTP_PORT = {{ service.ports.http }}
ROOT_URL = http://{{ service.domain }}:{{ service.ports.http }}/
LFS_CONTENT_PATH = {{ service.root }}/data/lfs
```
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
**Current implementation of `service`**<br />
It [currently works][working-service-asciinema], and we just need to add more services!
Every new corner case will be thoroughly investigated to provide the smoothest experience possible under BaguetteOS.
We currently use it for a few services, such as the nginx providing this very website.
Currently, there are no fancy environments, just plain directories.
**Future of `service`**<br />
First, we want to work on databases, to export data and get a simple backup service.
Then, we could let users manage their own services, but this is of little interest in practice since services are running under different users already.
The most useful thing to do right now is to provide new services.
[Come back to top](#top)
2020-04-23 17:51:38 +02:00
---
2020-04-25 04:45:44 +02:00
<a name="other-tools"></a>
### Other tools
2020-04-23 17:51:38 +02:00
<a name="libipc"></a>
**[LibIPC][libipc]: an IPC communication library** *nothing new, yet it still feels fresh*<br />
2020-04-25 04:45:44 +02:00
We use this communication library between our services.
2020-04-23 17:51:38 +02:00
1. Applications should talk to each other
2. We need services, not libraries<br />
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.
C library with Crystal bindings (other languages coming soon)
```Crystal
2020-04-23 17:51:38 +02:00
require "ipc.cr"
server = IPC::Service.new "MyService"
server.loop do |message|
# ...
end
```
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
That's easy to write [even in plain C](https://git.baguette.netlib.re/Baguette/libipc/src/branch/master/examples/pongd.c).
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
Its explanation goes beyond the scope of this page… but the tool is awesome and performances are crazy (we have to tell the world!).
[Just go and check!][libipc]
<red>Explain remote communications.</red>
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
2020-04-23 17:51:38 +02:00
---
2020-04-25 04:45:44 +02:00
<a name="build.zsh"></a>
2020-04-23 17:51:38 +02:00
<red>TODO.</red>
**[Build.zsh][build.zsh]: makefile creation.** *for mere mortals*<br />
Build.zsh creates a makefile from a simple declarative configuration file.
It can replace most build systems.
---
<red>TODO.</red>
**[tap-aggregator][tap-aggregator]: quality assurance & test results aggregation**<br />
---
<red>TODO: better explanation.</red>
**[Webhooksd][webhooksd]: verify recipes.**<br />
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
<a name="slotting"></a>
# 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.
<red>TODO</red>
**Problem:** what happens when two programs need a different version of a library?<br />
**Problem:** what happens when two libraries are compatible but you want both on your system (see libressl and openssl)?<br />
**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.
<red>TODO</red>
**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](#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
<a name="roadmap"></a>
# Roadmap
<red>TODO</red>
We currently aim at providing a rootfs with our tools, when we will have enough spare time to contribute.
2020-04-25 04:45:44 +02:00
**Web interface** is for later: we need more time to design its graphical components.
On the other hand, back-end should be straightforward.
<a name="contact"></a>
# Contact
2020-04-23 17:51:38 +02:00
2020-04-25 04:45:44 +02:00
Do not hesitate to come on our [Mattermost][mattermost].
We will soon have bridges on XMPP and IRC, stay tuned!
# Just dropped things
80211d
networkctl
firewalld
ajouter des outils de gestion (suppression, modification) de préfixes dans lenvironnement (PATH, LD_LIBRARY_PATH, PKGCONFIG_PATH, etc.). À faire a minima dans /etc/profile.
partitionnement et formatage des partitions
Avoir un programme qui permet de retrouver de quel paquet provient un fichier (un reverse apk manifest).
[mattermost]: https://team.baguette.netlib.re/
2020-04-23 17:51:38 +02:00
[service]: https://git.baguette.netlib.re/Baguette/service
[package]: https://git.baguette.netlib.re/Baguette/package
[packaging]: https://git.baguette.netlib.re/Baguette/packaging
[build.zsh]: https://git.baguette.netlib.re/Baguette/build.zsh
[libipc]: https://git.baguette.netlib.re/Baguette/libipc
2020-04-25 04:45:44 +02:00
[todod]: https://git.baguette.netlib.re/Baguette/todod
2020-04-23 17:51:38 +02:00
[webhooksd]: https://git.baguette.netlib.re/Baguette/
[tap-aggregator]: https://git.baguette.netlib.re/Baguette/tap-aggregator
2020-04-25 04:45:44 +02:00
[baguette-gitea]: https://git.baguette.netlib.re/
2020-04-23 17:51:38 +02:00
[baguette-rc]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/rc
[baguette-profile]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/rc/profile
[recipes]: https://git.baguette.netlib.re/Baguette/recipes/
2020-04-23 17:51:38 +02:00
[recipe-hello]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/hello/recipe.spec
[recipe-dhcpcd]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/dhcpcd/recipe.spec
[recipe-alsautils]: https://git.baguette.netlib.re/Baguette/recipes/src/branch/master/alsa-utils/recipe.spec
2020-04-25 04:45:44 +02:00
[autotools]: https://www.gnu.org/software/automake/manual/html_node/Autotools-Introduction.html
2020-04-23 17:51:38 +02:00
[toybox]: http://www.landley.net/toybox/
[cruxinit]: https://crux.nu/gitweb/?p=ports/core.git;a=blob;f=rc/rc;h=26b8ca08d67208ceda4d4004c8333d362bcdc689;hb=HEAD
[ksh]: https://github.com/att/ast
[zsh]: https://www.zsh.org/
[libarchive]: https://libarchive.org/
[bsdcpio]: https://libarchive.org/
[bsdtar]: https://libarchive.org/
[m4]: https://www.gnu.org/software/m4/m4.html
[gmake]: https://www.gnu.org/software/make/
[proot]: https://man.openbsd.org/proot
2020-04-25 04:45:44 +02:00
[zig]: https://ziglang.org/
2020-04-23 17:51:38 +02:00
[openbsd]: https://openbsd.org/
[pfsense]: https://www.pfsense.org/
[alpine]: https://alpinelinux.org/
[crux]: https://crux.nu/
[inferno]: http://www.vitanuova.com/inferno/index.html
[plan9]: https://9p.io/plan9/index.html
[morpheus]: https://morpheus.2f30.org/
[suckless]: https://suckless.org/
[cat-v]: http://cat-v.org/
2020-04-25 04:45:44 +02:00
[working-service-asciinema]: https://asciinema.org/a/0p2vGNA1TUmvq0s61Lu0r4TN6
[ruby-memory-bp]: https://web.archive.org/web/20160329122617/http://blog.rubybestpractices.com/posts/ewong/005-Avoiding-system-calls.html