NodeOS 1.0.0-RC3 "refactor"... with a Bonus

Image
@piranna

02:14 - 24 Jan 2017

After some hiatus, there has been some work here on the project, and after some work… here is it the (in)famous RC3 with the so much talked refactor :-D

It was known that NodeOS architecture was still too much dependent of the original centrilized design in part done due to the CUSL. This made it dificult to maintain because code was heavily cohexive, and the whole build process was painfully slow. After splittin it in several projects for each layer it was shown that this main project was almost empty having all the logic on each layer, so after some initial serious intention to port NodeOS to ARM once for all (but unsuccesful? More on this later), the conclusion was that it was needed to clean-up the code first. A lot. And so I did :-)

  • Now all the logic regarding the generation of NodeOS for each platform is moved to the main NodeOS project itself, making each layer and sub-project to generate just simple and focused products that later are aggregated. Just plain ol’ school UNIX filosophy. For example, nodeos-barebones now just only generates a .cpio.gz initram to be embedded in the kernel (and the kernel itself, but it’s planned to be moved out too in the foresee future), without worrying about what particular NodeOS flavor will use it since it will be later customized, or nodeos-usersfs now don’t have any dependency on the other layers, making it easier to understand how to create other custom users filesystems. It also convert and pack the different layers as the format needed by the target platform, being that a tarfile or an ext2 filesystem or whatever, customizing them by adding or removing specific files if needed.
  • nodeos-rootfs module has been finally deprecated and replaced by the nodeos-bootfs tool, that generate the /boot partition or ISO image only when needed. It was there for legacy reasons before making each user to have their own root filesystem, but it was just a no-op in the cases where there was no need for a boot partition, so finally it was removed.
  • One important point is that each layer now has its own tests, that help to easily and sooner identify the problems that could arise by making each layer more independent, and in fact some of them has appear during the process of adding them (and a test is not good enough if it doesn’t show some bugs ;-) ). One of the biggest missing testing areas was to check that the prebuild release images of NodeOS where in fact bootable, that has been fixed both by creating a wrapping module on top of the libblkid library to be able to detect the partitions by their UUID instead of hardcoded device, and by showing the Syslinux bootloader prompt for just 0.1 seconds so the test can be able to detect and hook on it and append console=ttyS0 to the kernel command line, so now it’s not only possible to capture its output and control the console but also the users can move the partitions around and add their own boot arguments without problems. The wrapper for libblkid has not be done without problems, due to the lack of documentation of how internally it works (at first I was not interested on compile it but just only to know how it detected the partitions UUIDs, because util-linux is a huge monolithic library) and later due to a lot of legacy code that prevented to compile it easily with recent tools (I needed to hack its code to make it compile with node-gyp…).
  • Since now each layer is more independent and has their own tests it makes sense to also generate their own prebuild images automatically, and the fact is that this has helped to improve the NodeOS build time A LOT. By (ab)using the prebuild-install module now they checks if there’s available a prebuild image for the target platform, and if so then it’s used instead of download its source code and compile it, and to don’t need to download useless build dependencies for them, I’ve also created the buildDependencies module to download them for you in case they are needed by reusing the devDependencies field. So, do you remember the infamous step of pick some microwave pop-corn and go to see a movie from the NodeOS build instructions? Well… now with a decent internet connection and a somewhat fast laptop, maybe you’ll not be able to finish your cup of coffee while using the BigRedButton script to build and test all the NodeOS supported architectures and platforms at once. Yes, so fast is it now :sweat_smile:
  • nodeos-cross-toolchain and the NodeOS layers build process now accept arguments following the QEmu scheme, and their generated products have been changued to follow them too. This has the side effect that now the $PLATFORM environment variable only define the format of the final products and has nothing to do with the architecture details. It also makes it easier to port to new platforms and architectures and to test them too by having a clear build matrix to follow. It keeps to convert the usage of specific “generic” CPUs identifiers to the more abstract Node.js architecture, so it would not be needed to be translated them several times but just once.
  • buildDependencies or nodeos-bootfs have not been the only modules created for this RC. tar2ext has been created to generate partition images for usersfs in a similar way to how cpio2tar works, and nodeos-mount-filesystems has been totally rewritten and splitted in the modules nodeos-boot-singleUser, nodeos-boot-singleUserMount and nodeos-boot-multiUser to improve flexibility in environments where it’s only desired to exec a single Node.js app instead of hosting a full multi-user environment. Not only that, that to ensure the single apps also run on an isolated environment similar to the one of the full NodeOS experience, the mechanism to create them has been put in the new jocker, the Javascript Docker module :-P By the moment it’s just an augmentated chroot, but being on an independent module would help to move forward to use real LXC containers in the future in a simple way.

As you can see there has been a lot of work here :-D But there’s still a lot to do. For example, buho module needs to be improved to be able to check on dependencies upgrading to update them too in a similar way to how Greenkeeper works (maybe we could integrate it?), or Node.js itself it’s stalled on the 6.x branch due to cross-compilation problems on the version of the v8 Javascript engine included in Node.js 7.x, or the need to update fuse-bindings to make use of FUSE 3.0.0 or support several standard libraries on the prebuild images (glibc and musl) publishing releases of both, but definitelly the most important things that need to be fixed is the support to exec interactive console apps in nsh and the removal of the several projects forks by getting them to be merged upstream, so let’s start to give them some pressure ;-) Oh, and as always, improve the documentation of the different sub-projects, of course…

Regarding ARM, now both nodeos-cross-toolchain and nodeos-nodejs support them and host prebuild images for Raspberry Pi 2, but NodeOS itself can be tested due to problems with QEmu, seems regarding to the loading address of the kernel image. It needs to check if they run in fact on real hardware to confirm that’s a QEmu problem, but until that it has been added support for the Raspberry Pi original because it now has been added support for the board (also untested for the same reasons), and plan to add support for the versalitepb board since it’s the default one for ARM machines on QEmu and one year ago I was able to boot NodeOS on it (althought getting a kernel panic when executing the /init binary), so at least let’s hope to be able to tests the ARM architecture too :-)

And now, the…

Bonus

The RC3 was published last week, but I have been really busy this week and also caught a cold so my mind was not in the perfect state to concentrate and write this essay, so since I had back in my mind the feeling that I almost got something “interesting” to work, I employed the few spare time I got to work on it a little bit each time, and finally this morning I got it:

[email protected]:~/Proyectos/NodeOS$ npm run docker

> [email protected] docker /home/piranna/Proyectos/NodeOS
> scripts/docker

mount procfs: Resource busy
Hello! I'm a user init script :-)
Welcome to NodeOS!: username:  nodeos
·                 : password:  
~ > 

Yes, that’s it: NodeOS fully booting inside Docker!!! :-D The problem with usersfs has been solved thanks to the refactor by being able now to convert the generated tarfile to a Docker Volume and assigning it directly to /tmp inside the NodeOS filesystem hierarchy, and it’s configured to support FUSE filesystems (needed by ExclFS) and OverlayFS (needed by the by-user root filesystem). It’s fairly experimental since I needed to tweak some things, for example I needed to change the Docker storage driver to overlay2 because the default aufs one was freezing my machine needing to reboot, and that makes it impractical for debugging it and make it work (maybe now that’s fixed it could work but it’s untested, YMMV). To be honest I’ve needed to do some tricks like disable the usage of node-bin-getty to manage the console because I was not being able to make it owner of the console (maybe I’m doing something wrong?) and exec directly logon and also seems to be there a “little” problem with the user ID:

~ > pstree 
init
├── exclfs
├─┬ nsh
│ └── pstree
└── nodeos-reverse-

~ > ls proc/
[ '1',
  '110',
  '16',
  '45',
  '47',
  'acpi',
  ...

As we can see here, although we login with the nodeos account we are having the UID 0 and seeing the administrative processes, but at least it works to show how much few processes with administrative permissions are needed for a fully working system, that’s one of the purposses of NodeOS :-D I’m not sure if it could be a problem on NodeOS (I have checked the files directly on the layers managed by Docker and they have the correct UIDs and GIDs) or about Docker ignoring the UIDs and using just only root for everything because the LXC containers already isolate the processes from the underlying system so by design it’s supposed they are given the least possible permissions (I didn’t found any example that execute a process not as root inside a Docker instance so far…). In any case, that’s a huge milestone and promise some very interesting things for the future of NodeOS ;-) Next step, vagga ;-)


0 Comments

NodeOS is made possible by its many contributors around the world. Source code licensed under the MIT license.

Made with ❤️
and 🍺