Project Information
Organization: Fedora Project
Fedora SIG: Fedora DotNet SIG
Student: Amitosh Swain Mahapatra amitosh.swain@gmail.com
Possible mentor: Radka (rhea) Janek radka.janek@redhat.com
Contact Information
amitosh.swain@gmail.com | |
PGP Key | 89A3A2B0 |
Time zone | UTC +5:30 |
Freenode IRC nick | amitosh |
Github | Agathver |
Blog | https://amitosh.in |
OriginalASM |
Proposal
Abstract
This project aims to create a .NET core wrapper library for systemd, a service manager and process hypervisor in modern Linux systems. Using this library, actions such as monitoring and controlling the state of services, controlling power, devices and other system aspects of the underlying system can be performed from a language running on .NET, such as C#.
Introduction
systemd
is a suite of basic building blocks for a Linux system. It provides a system and service manager and starts the rest of the system. It also includes a logging system, utilities to control basic system configuration like the hostname, date, locale etc. systemd provides a way for programmatic access to systemd actions through the DBus API. This library would use DBus to interact with systemd daemon and offer monitoring and control over services running on the system.
Terms
- A
Job
is a task that has been queued to the systemd job queue. It can be any request to systemd such as a request to start a service or a request to restart the system. Everysystemd
command to perform an action, creates a job which is identified by its ID, and is queued to the systemd job queue.systemd
then processes the job sequentially. A job can also be cancelled before it is executed. This results in the removal of the job from the systemd job queue. - A
Unit
is an individual systemd service. It can represent a device, a daemon service, or a repeating action i.e., timer. It is mapped to a systemd unit file, which serves as its identifier. - A
User
is an entity, under which context a process can run. Theuser
of a process determines the actions it can perform. - A
Session
is a group of processes which run under the control of a single user. It usually refers to a shell session. Each interactive login by the user creates a session. - A
Seat
refers to a set of hardware peripherals using which a user can start an independent interactiveSession
.
systemd
is broken down into various services which are started by systemd itself. These services along with systemd, provide the basic services required by Linux system.
Service | Role |
---|---|
manager | The principal component of systemd, which manages services and basic system configuration. |
journald | Provides an event logging system. |
logind | Manages user login sessions, and provides a convenient way to logout, shutdown, restart etc. |
networkd | Controls network related settings |
timedated | Manages time-date related settings |
Project Goals
Create a .NET wrapper for systemd, that will be able to:
- Fetch a list of services available on the host.
- Fetch a service by its unit ID.
- Control the state of a service - enable, disable, start, stop, restart, reload and kill.
- Control the power state of the system - restart, shutdown, suspend and halt.
- Create events to listen for various systemd signals.
Optional Goals (if time permits)
- Logging interface to log using systemd-journald
Deliverables
1st evaluation
- Implementation of the following interfaces in C#, and the binding using DBus APIs.
org.freedesktop.systemd1.Manager
org.freedesktop.systemd1.Unit
org.freedesktop.systemd1.Job
- Library will be able to query a service’s status, start, stop and restart services. It will also list all currently running services.
2nd evaluation
- Implementation of systemd signals.
- Implementation of the following interfaces in C#, and the binding using DBus APIs.
org.freedesktop.login1.Manager
org.freedesktop.login1.User
org.freedesktop.login1.Session
org.freedesktop.login1.Seat
- Library will be able to shutdown and reboot the host, schedule reboots, display and logout users and their sessions.
3rd evaluation
A systemd wrapper library, published as a nuget package.
Implementation
We will be implementing the interface to systemd service manager and the systemd-logind manager. We are going to use the DBus API of systemd to make inter-process calls to systemd daemon. For DBus in C#, We will be using Tom Deseyn’s Tmds.DBus library.
Advantages of DBus
- No dependency on presence of specific system libraries.
- 100% purely portable and managed code.
Advantages of Tmds.DBus over other libraries
- The library is entirely based on C# async/await pattern, for which it is easier to implement an async/await based API for systemd. It will be especially attractive to users implementing with ASP.NET async controller actions.
- As a side effect of being based on async/await, developing using async/await will result in cleaner and easier implementation.
Alternatives considered
P/Invoke wrapper on libsystemd1.so
Disadvantages
- Platform dependent, needs testing in all supported architectures.
- Running code using such a library might need multi-arch support, if not compiled carefully.
NDesk.DBus/Mono.DBus library for systemd.
This is another library that enables to make us DBus calls from .NET and Mono.
- Disadvantages of NDesk.DBus
- Has not tested been against .NET core.
- Does not appear to be maintained currently.
The library
The library will contain a set of interfaces that specifies the general API for interacting with systemd from .NET. Any implementations are required to provide the same set of methods. This set of interfaces will make the primary part that a consumer using the library will use.
API
All interfaces will contain both, the synchronous and asynchronous versions of all the supported systemd operations. As per the .NET conventions, all the async counterparts will be suffixed with Async
.
Namespace Systemd
Class | Description |
---|---|
Systemd | Main entrypoint to the library, returns default implementations of ISystemdManager and ISystemdLogind manager.
|
Systemd
This class will serve as the main entrypoint to the library. It will return implementations of ISystemdManager and ISystemdLogind manager.
Method | Description |
---|---|
GetManager | Returns an interface to systemd manager. |
GetLoginManager | Returns an interface to systemd-logind manager. |
Namespace Systemd.Manager
Interface | Description |
---|---|
ISystemdManager | Represents the systemd Manager |
ISystemdUnit | Represents a systemd unit |
ISystemdJob | Represents a systemd job |
ISystemdManager
ISystemdManager
interface exposes the functionality of systemd service manager.
Method | Description |
---|---|
ListUnits | Return a list of service units currently loaded by systemd |
GetUnit | Returns a service unit, specified by its unit ID. |
EnableUnitFiles | Enables a list of systemd unit files |
DisableUnitFiles | Disables a list of unit files |
SetEnvironment | Sets a systemd environment variable which is passed on to all services started by systemd |
UnsetEnvironment | Unsets a previously defined systemd environment variable. |
Reload | Reloads all unit files |
ListUnitFiles | Lists all unit files found in disk. |
These methods, when invoked with appropriate parameters, will return a object of a class which implements ISystemdUnit
interface.
ISystemdUnit
The ISystemdUnit
interface is a representation of an individual systemd unit file. Using an instance of an implementation that implements this interface, the consumer will be able to start, stop, query status, restart and kill the underlying service. The ISystemdUnit
interface will be modelled after The interface will contain the following methods:
Method | Description |
---|---|
Start | Attempts to start the unit. |
Stop | Attempts to stop the unit. |
Restart | Attempts to restart the unit. The unit is started if it is not running. |
Kill | Kills the unit. |
Reload | Attempts to reload the unit. The unit is started if it is not running. |
ReloadOrRestart | Attempts to reload the service, if the service provides such an action, else restarts the service. |
ReloadOrRestartIfRunning | Attempts to reload the service, if the service provides such an action, else creates a request to restart the service only if the unit is already running. Calls systemd dbus method ReloadOrTryRestart .
|
RestartIfRunning | Creates a request to restart the service, only if it is running. Calls systemd dbus method TryRestart .
|
Every method will return an instance of an implementation of ISystemdJob
. It represents a systemd job with the job queue, which can be used later to check the status or cancel the job.
ISystemdJob
The ISystemdJob
represents a systemd job in the job queue. It will have the following methods and properties:
Method | Description |
---|---|
Cancel | Cancels the job. Can only be called before the job has been executed by systemd. |
This pattern will leave the scope for extending or replacing the default implementation of the ISystemdManager
, such as connecting to a remote host using SSH and proxying calls between the local and remote systems.
Namespace Systemd.Logind
Interface | Description |
---|---|
ISystemdLogindManager | Represents the systemd-logind manager. |
IUser | Represents a system user in the host. |
ISession | Represents a session started by an user. |
ISeat | Represents a seat in a multi seat system. |
ISystemdLogindManager
ISystemdLogindManager
interface exposes the functionality of systemd service manager.
Method | Description |
---|---|
GetSession | Get a session by its session ID or PID, |
GetUser | Get an user by its ID or PID, |
GetSeat | Get a Seat by its ID or PID, |
AttachDevice | Attaches a device by its /dev node to a seat
|
RemoveDevice | Removes a device attached to a seat. |
FlushDevices | Removes all device attachments made by AttachDevice and restores the default attachment of all devices. |
PowerOff | Powers off the host. |
Reboot | Reboots the host. |
Suspend | Suspends the host. |
Hibernate | Hibernates the host. |
HybridSleep | Puts the host to hybrid sleep. |
CanPowerOff | Returns if the host supports power off state (S5) and the calling user has the privileges to perform a shutdown. |
CanReboot | Returns if the host supports reboot and the calling user has the privileges to perform a reboot. |
CanSuspend | Returns if the host supports suspend to RAM and the calling user has the privileges to perform a suspend to RAM (sleep mode). |
CanHibernate | Returns if the host supports suspend to disk and the calling user has the privileges to perform a suspend to disk. |
CanHybridSleep | Returns if the host supports hybrid sleep (suspend to RAM and subsequent suspend to disk, if not awaken for an extended period of time) and the calling user has the privileges to perform a shutdown. |
ScheduleShutdown | Schedules a shutdown |
CancelScheduledShutdown | Cancels a previously scheduled shutdown |
IUser
The IUser interface represents a User
on the host.
Method | Description |
---|---|
Kill | Forcibly kills all processes started by the user and logs out. |
Terminate | Terminates the user and sessions started by the user. |
ISession
The ISession interface represents a shell session started by a user.
Method | Description |
---|---|
Lock | Locks the session. Shows a lock screen for graphical sessions. |
Unlock | Unlocks the session |
Kill | Kills the session |
ISeat
The ISeat interface represents a physical seat on a multi-seat capable system.
Method | Description |
---|---|
ActivateSession | Activates a session identified by session ID on the seat |
Terminate | Terminates the session |
Signals
systemd signals provide an way to notify listeners about various system events. Signals will be implemented as standard .NET events on ISystemdManager and ISystemdLogindManager.
+ Signals of systemd managerSignal | Description |
---|---|
UnitAdded | Raised when a new unit is added. Maps to underlying systemd signal UnitNew .
|
UnitRemoved | Raised when a unit is removed. |
UnitFilesChanged | Raised when a unit file is modified in any manner. |
JobAdded | Raised when a new job is queued in systemd job queue. Maps to underlying systemd signal JobNew .
|
JobRemoved | Raised when a job is removed from the systemd job queue. |
StartupFinished | Raised after system startup sequence is completed. |
Reloading | Raised when systemd is reloading untis. |
Signal | Description |
---|---|
SessionCreated | Raised when a new session is created. Maps to underlying systemd signal SessionNew .
|
SessionRemoved | Raised when a session is removed. |
UserAdded | Raised when a new user logs into the system. Maps to underlying systemd signal UserNew .
|
UserRemoved | Raised when a user logs out of the host, and exiting all sessions. |
SeatAdded | Raised when a new seat is attached to the host. Maps to underlying systemd signal SeatNew .
|
SeatRemoved | Raised when a seat is removed from the host. |
ShuttingDown | Raised before starting the shutdown process, consumers can perform pre-exit tasks after receiving this signal. Maps to underlying systemd signal PrepareForShutdown
|
PrepareForSleep | Raised before transitioning into a sleep or hybrid sleep state. Consumers can pause any interactive operations on receiving this signal. |
Implementation using DBus
The default implementation included with this library will be an implementation of ISystemdManager
which will use DBus as its medium to connect to the local host’s DBus running on the system
bus and the session
bus.
The systemd service manager is available at org.freedesktop.systemd1.Manager
DBus interface in the system
bus and session
bus. The systemd interface on system bus is used to control system wide services, and the interface on session bus is used to control user services.
The systemd-logind is available at org.freedesktop.login1.Manager
DBus interface in the system
bus.
The default implementation will be set of classes under the implementation namespace. The classes will proxy all method calls to a DBus interfaces using Tmds.DBus.
The general pattern for all classes in the implementation will be: Constructor that accepts the underlying DBus interface for the class. Methods that when invoked will call methods on the DBus interface.
Entrypoint
The main entry point to the library will be a singleton Systemd
class. This singleton class will return an instance of another singleton classes that implement the methods of the ISystemdManager
or the ISystemdLogindManager
interface.
Pitfalls
systemd-logind functionality such as shutdown and restart cannot be tested in CI
Shutdown and restart will stop a system and start it again. Tests cannot be made in virtual machine based CI systems.
Solution: Using docker containers running systemd
A docker container can contain logind tests for reboot, and shutdown, which will be started on receiving a signal from the test runner host. The host will then check for desired outcome of the test by using the API of docker daemon.
Multi-seat management, session locking and unlocking cannot be tested in CI
Multi-seat and session locking is only relevant when the system has at least 2 display units, CI environments and docker containers are headless.
Current workaround: Test locally (inconvenient)
I will be testing the code on my desktop, connected to two monitors, two keyboards and two mice, to make a multi-seat system.
Possible Solutions:
Here are some alternatives to consider in the long run:
Test using nested virtual machines
We can setup QEMU-KVM virtual machines, inside the CI environment, with two display units and test within it. However, this will be inconvenient as it requires moving huge files (8-9 GB) around (as CI services do not cache files), and due to memory constraints inside a CI environment.
Testing on a cloud virtual machine The same KVM virtual machines can be made to run inside a cloud hosted virtual machine of required size. This is more practical, but requires a lot of work.
Timeline
Phase I - Learning, ideation and preparation
- May 5 - second week of May:
- Learn more about systemd and its dbus interface.
- Discuss with the community to decide on the exact particulars of the implementation, library pattern, code styles, possible pitfalls etc.
- Learn about publishing packages to NuGet.
- Third week May - 1st of June (during community bonding period):
- Setting up IDEs, Git repositories etc.
- Setting up a local testing environment.
- Creating classes and interfaces for systemd for use with the DBus API.
Phase 2 - Coding for the systemd manager:
- Week 1 (1st June - 6th June):
- Connecting to a running systemd instance.
- Handling and generating proper exceptions.
- Week 2 (7th June - 13th June):
- Listing active services and their status.
- Finding an installed service by its id.
- Week 3 (14th June - 21nd June):
- Enabling and disabling unit files.
- Start, Stop, Kill, Restart and Reload units.
- Week 4 (21nd - 26th June):
- Fix bugs and write additional tests.
- Prepare for 1st term evaluation.
- Week 5 (29th June - 6th July):
- Begin implementing the systemd-logind wrapper.
- Library will now be able to shutdown, restart and halt the host.
- Week 6 (7th July - 13th July):
- Fetching users, sessions and seat from logind.
- Operations on users, sessions and seats - Kill, Terminate
- Week 7 (14th July - 20th July):
- Test seat operations on a real multi-seat setup.
- Week 8 (21st July - 26th July):
- Write more tests
- Prepare for 2nd term evaluation
Phase III - Testing, Optimization and Documentation
- Week 9 (29th July - 5th August):
- Resolve discovered issues.
- Incorporate suggestions by the community.
- Check test code coverage of the library
- Test on real hosts
- Week 10 (6th August - 12th August):
- Write more tests if required.
- Review inline documentation and fix them
- Prepare HTML documentation
- Document testing processes.
- Week 11 (12th August - 18th August):
- Buffer time for unforeseen circumstances.
- Week 12 (19th August - 25th August):
- Publish package to nuget, after approval.
- Prepare for final evaluation.
About Me
Educational background
I am currently a second year B.Tech student in computer science and engineering at College of Engineering and Technology, Bhubaneswar, India. How computers and software worked have fascinated me since my middle school days. My first exposure to programming was with C in 6th grade. Since then, I have been constantly exploring new areas in programming. I chose to study computer science, in order to satisfy my curiosity for learning new things in the field of computer science and IT, and also due to fact that I perform academically well in computer science courses, due to my interest in the subject.
Why did I choose Fedora ?
My first exposure to Linux world was thorough Fedora. It was back in my 9th grade when I first installed Fedora 16 (Verne). So I was always interested to contribute back to the project if I got any chance. Fedora project is also a very good project with a large user base, so any effort in contributing the project will help a large community.
Besides, the project idea of building a .NET core wrapper to systemd was appealing as I’m familiar with systemd and its working, as well as I have good coding experience in .NET in general.
Why did I choose this project ?
.NET core is a budding open source platform, based on the foundation of the well tested .NET framework. It is cross-platform and has the potential to become a great server side framework, in near future.
However, one of the of hurdles for developing solutions in .NET in Linux has been the lack of decent libraries for system integration. This project is a step towards bridging those gaps and bringing a deeper system integration to .NET core applications. Experience I have been writing code in .NET over last four years. I am confident enough about my language skills. I have completed a number of freelance projects using .NET. I also have a good experience in object oriented programming concepts and software testing.
Being a long time Fedora user and a programmer with curiosity, I am familiar with the internal workings of a Linux system and system APIs. I have worked with DBus (though mostly in Python and Go) as part of two hobby projects.
Last summer, I had interned at an educational startup (and subsequently worked part time of 8 months) where I have worked with PHP and .NET (on Windows) and managing CentOS and Ubuntu servers. I had written some simple systemd service unit files, and python code that used python bindings for systemd APIs.
Contributions to open source
- Active contributor to a project called
bcrypt
. It is a very widely used NodeJS module that provides bcrypt hashing capabilities, which is commonly used to store passwords in hashed form. - Member of the technical society of our college where we promote the use of FOSS technology among the students. I also help out students who decide to start using Fedora, Ubuntu or any other Linux system.
- Answering questions on StackOverflow, CodeProject and AskFedora about FOSS technologies as well as general programming and help questions.
Previous Google Summer of Code Experience
This is my first application to Google Summer of Code programme.
Commitments and engagements during GSoC
I have discussed my proposal with my mentor and have agreed upon the timeline and implementation. If selected, I’ll give my full dedication to the project. I have no prior commitments during the month of June to August and will be able to provide 30 hours a week to the project.
- May 2 to May 20: I have my end semester exams from during this period. Since this period lies during the community bonding period, I expect it to have very little effect on the implementation of the project. I have one paper per week, so I will be able to devote my free time to research about
systemd
dbus APIs, to discuss the implementation with the community, and to learn about publishing to NuGet. - August 3rd week onwards: My classes are expected to begin from 3rd week of August. During that period, I would be able to give 20-25 hours per week.