A lightweight gem for interact with Systemd.
If your goal is to develop software to quickly manage systemd services or journalctl logs, this gem is for you! 😁
- Lightweight
- Expressive classes and methods
- Manage Systemd's services lifecycle with minimal effort!
- Extract and manipulate Journalctl logs with a single action!
- Installation
- Dependencies
- Usage
- Manage services
- Create a Systemdy Service object for control a service
- Check if the provided service exist
- Check if the provided service is enabled
- Check if the provided service is active
- Check the current status of the provided service
- Display all the properties for the provided service
- Get service port
- Get service protocol
- Start the service
- Restart the service
- Stop the service
- Enable the service
- Disable the service
- Reload the service
- Mask the service
- Unmask the service
- Bonus tip: execute systemctl commands without prompt the password
- Manage Journalctl logs
- Contributing
- Note for testing
- License
- Useful links and resources
- Acknowledgements
Add this line to your application's Gemfile:
gem 'systemdy'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install systemdy
The only dependecy you need is systemd installed on your system (specifically libsystemd or the older libsystemd-journal) in order to use the gem. Currently the gem support systemd 249 or higher.
After installing the gem, the first step is to require it:
require 'systemdy'
The first goal of this gem is to manage a systemd's service with minimal effort.
This section provides an overview of the Systemdy::Service class for managing the life cycle of a systemd's service.
The first step is to create a new instance of the Systemdy::Service class for control the desired service
my_postgresql_service = Systemdy::Service.new('postgresql')
Once our object has been instantiated, you can check if the service is installed on your system
my_postgresql_service.exist?
For check if a service is installed on your system without create a new instance of the Systemdy::Service class
Systemdy::Utility::Validator.check_if_a_service_exist('postgresql')
if the provided service is installed on your system this methods return true, otherwise return false.
For check if a service is enabled
my_postgresql_service.is_enabled?
if the provided service is enabled this method return true, otherwise return false.
For check if a service is active
my_postgresql_service.is_active?
if the provided service is active this method return true, otherwise return false.
For check the current status of the service
my_postgresql_service.status
Once executed, this method return an hash with all the essential service's information like this:
{ "Id"=>"postgresql.service",
"Description"=>"PostgreSQL RDBMS",
"ExecMainPID"=>"48615",
"LoadState"=>"loaded",
"ActiveState"=>"active",
"FragmentPath"=>"/lib/systemd/system/postgresql.service",
"ActiveEnterTimestamp"=>"Thu 2022-09-29 17:13:07 CEST",
"InactiveEnterTimestamp"=>"Thu 2022-09-29 17:12:44 CEST",
"ActiveExitTimestamp"=>"Thu 2022-09-29 17:12:44 CEST",
"InactiveExitTimestamp"=>"Thu 2022-09-29 17:13:07 CEST"
}
For check all the properties of the service
my_postgresql_service.properties
Once executed, this method return an hash with all the service's properties like this:
{ "Type"=>"oneshot",
"Restart"=>"no",
"NotifyAccess"=>"none",
....
}
To extract the value of a specific property
my_postgresql_service.properties["MemorySwapMax"]
For retrieve a service port
my_postgresql_service.port
Once executed, this method return the provided service port:
"5432"
if the provided service has no available port, this method return a message like this:
"[name_of_the_service].service has no port available"
For retrieve a service protocol
my_postgresql_service.protocol
Once executed, this method return the provided service protocol:
"tcp"
if the provided service has no available protocol, this method return a message like this:
"[name_of_the_service].service has no protocol available"
For start the service
my_postgresql_service.start
For restart the service
my_postgresql_service.restart
For stop the service
my_postgresql_service.stop
For enable the service
my_postgresql_service.enable
For disable the service
my_postgresql_service.disable
For reload the service
my_postgresql_service.reload
For mask the service
my_postgresql_service.mask
For unmask the service
my_postgresql_service.unmask
The methods start, restart, stop, enable, disable, reload, mask and unmask detect non-root users and automatically execute the methods with sudo.
By default, sudo needs that a non-root user(in this case you) is authenticated using a password for complete the method execution. This is a great thing, but some times you may need to execute this methods without type the password.
In this case you need to configure sudo without a password.
The first step for achieve this is gain root access:
non_root_user@my-machine:~$ sudo -i
[sudo] password for non_root_user:
After provided the correct password backup your /etc/sudoers file by typing the following command:
root@my-machine:~# cp /etc/sudoers /root/sudoers.bak
Next step is edit the /etc/sudoers file by typing the visudo command:
root@my-machine:~# visudo
Append/edit the following lines in the /etc/sudoers file and substitute 'your_account_name' with your linux account name.
'your_account_name' ALL=(ALL) NOPASSWD: /bin/systemctl
This line anable you to run ‘systemctl’ commands without a password.
Save with CTRL + X
Type 'exit' on your terminal as follows:
root@my-machine:~# exit
Exit from root session and you are ready to go! 😎
The second goal of this gem is to provide a set of useful methods for retrieving journalctl log data.
This section provides a brief overview of the Systemdy::Journal class for managing journalctl log information.
Sometimes we need to check if the kernel is working properly or if something went wrong to get useful information to help us fix the problem.
For getting the kernel logs
Systemdy::Journal.display_kernel_logs
This class method executed with no arguments return an array with:
- a default size of 10 (the last 10 lines of log)
- a start period not older than '00:00 AM' o' clock (today)
- an end period not newer than the method execution timenow
Obviously this method allows you to filter the kernel logs by passing 3 positional arguments:
-
since: a start period not older than the specified date
-
to: an end period not older than the specified date
-
lines: the exact number of last log lines
For example:
If you want to analyze the last 50 log lines ranging from a month ago to 10:00 of the current day:
Systemdy::Journal.display_kernel_logs(since: '1 month ago', to: '10:00', lines: 50)
If you want to analyze the last 20 log lines ranging from a week ago to yesterday:
Systemdy::Journal.display_kernel_logs(since: '1 week ago', to: 'yesterday', lines: 20)
You can also filter the logs by specific dates in the format YYYY-MM-DD for example:
Systemdy::Journal.display_kernel_logs(since: '2022-08-27', lines: 200)
If the passed arguments not match anything the method return an array with a message like this:
["-- No entries --"]
Sometimes we need to know if our system is working properly at boot time and if something went wrong to get useful information to help us fix the problem.
For getting the boot logs
Systemdy::Journal.display_boot_logs
This class method executed with no arguments return an array with:
- a default size of 10 (the last 10 lines of log)
- a start period not older than '00:00 AM' o' clock (today)
- an end period not newer than the method execution timenow
Obviously as for the previous method, you can filter the boot logs by passing 4 positional arguments:
-
argument: in this case the boot's number
-
since: a start period not older than the specified date
-
to: an end period not older than the specified date
-
lines: the exact number of last log lines
For example:
If you want to analyze the last 50 log lines of the second boot ranging from a month ago to 10:00 of the current day:
Systemdy::Journal.display_boot_logs(argument: 2, since: '1 month ago', to: '10:00', lines: 50)
If you want to analyze the last 20 log of the third boot lines ranging from a week ago to yesterday:
Systemdy::Journal.display_boot_logs(argument: 3, since: '1 week ago', to: 'yesterday', lines: 20)
You can also filter the logs by specific dates in the format YYYY-MM-DD for example:
Systemdy::Journal.display_boot_logs(since: '2022-08-27', lines: 200)
If the passed arguments not match anything the method return an array with a message like this:
["-- No entries --"]
Another common task is to filter logs based on the unit that we need information on.
To do this, we just simply need to pass the name of the unit as argument, for example we need to analyze postgresql unit logs:
Systemdy::Journal.display_unit_logs(argument: 'postgresql')
In this case the class method return an array with:
- a default size of 10 (the last 10 lines of log)
- a start period not older than '00:00 AM' o' clock (today)
- an end period not newer than the method execution timenow
Obviously this method require the unit's name as argument, if executed with no arguments return a message like this:
"display_unit_logs require an argument!"
As for the previous method, you can filter the unit logs by passing 4 positional arguments:
-
argument: in this case the unit's name
-
since: a start period not older than the specified date
-
to: an end period not older than the specified date
-
lines: the exact number of last log lines
For example:
If you want to analyze the last 50 log lines of the potsgresql service ranging from a month ago to 10:00 of the current day:
Systemdy::Journal.display_unit_logs(argument: 'postgresql', since: '1 month ago', to: '10:00', lines: 50)
If you want to analyze the last 20 log lines of the potsgresql service ranging from a week ago to yesterday:
Systemdy::Journal.display_unit_logs(argument: 'postgresql', since: '1 week ago', to: 'yesterday', lines: 20)
You can also filter the logs by specific dates in the format YYYY-MM-DD for example:
Systemdy::Journal.display_unit_logs(argument: 'postgresql', since: '2022-08-27', lines: 200)
If the passed arguments not match anything the method return an array with a message like this:
["-- No entries --"]
To find all messages related to a particular group, we just simply need to pass the GUID of the group as argument, for example:
Systemdy::Journal.display_group_id_logs(argument: 1000)
In this case the class method return an array with:
- a default size of 10 (the last 10 lines of log)
- a start period not older than '00:00 AM' o' clock (today)
- an end period not newer than the method execution timenow
Obviously this method require the GUID as argument, if executed with no arguments return a message like this:
"display_group_id_logs require an argument!"
As for the previous method, you can filter the GUID logs by passing 4 positional arguments:
-
argument: in this case the GUID
-
since: a start period not older than the specified date
-
to: an end period not older than the specified date
-
lines: the exact number of last log lines
For example:
If you want to analyze the last 50 log lines of the GUID 1000 ranging from a month ago to 10:00 of the current day:
Systemdy::Journal.display_group_id_logs(argument: 1000, since: '1 month ago', to: '10:00', lines: 50)
If you want to analyze the last 20 log lines of the GUID 1000 ranging from a week ago to yesterday:
Systemdy::Journal.display_group_id_logs(argument: 1000, since: '1 week ago', to: 'yesterday', lines: 20)
You can also filter the logs by specific dates in the format YYYY-MM-DD for example:
Systemdy::Journal.display_group_id_logs(argument: 1000, since: '2022-08-27', lines: 200)
If the passed arguments not match anything the method return an array with a message like this:
["-- No entries --"]
To find all messages related to a particular user, we just simply need to pass the UID of the user as argument, for example:
Systemdy::Journal.display_user_id_logs(argument: 1000)
In this case the class method return an array with:
- a default size of 10 (the last 10 lines of log)
- a start period not older than '00:00 AM' o' clock (today)
- an end period not newer than the method execution timenow
Obviously this method require the UID as argument, if executed with no arguments return a message like this:
"display_user_id_logs require an argument!"
As for the previous method, you can filter the UID logs by passing 4 positional arguments:
-
argument: in this case the UID
-
since: a start period not older than the specified date
-
to: an end period not older than the specified date
-
lines: the exact number of last log lines
For example:
If you want to analyze the last 50 log lines of the UID 1000 ranging from a month ago to 10:00 of the current day:
Systemdy::Journal.display_user_id_logs(argument: 1000, since: '1 month ago', to: '10:00', lines: 50)
If you want to analyze the last 20 log lines of the UID 1000 ranging from a week ago to yesterday:
Systemdy::Journal.display_user_id_logs(argument: 1000, since: '1 week ago', to: 'yesterday', lines: 20)
You can also filter the logs by specific dates in the format YYYY-MM-DD for example:
Systemdy::Journal.display_user_id_logs(argument: 1000, since: '2022-08-27', lines: 200)
If the passed arguments not match anything the method return an array with a message like this:
["-- No entries --"]
We ❤️ pull requests from everyone.
Everyone interacting in the systemdy's project codebase is expected to follow the code of conduct.
If you wanna develop a new feature:
-
Fork this project
-
Clone the repo with the following command:
git clone [email protected]:your-username/systemdy.git
-
Install dependencies with:
bin/setup
-
Make your changes
-
Write tests.
NOTE: For a correct testing procedure read our Note for testing
-
Make the tests pass with the following command:
rake spec
-
Add notes about your changes to the
CHANGELOG.md
file -
Write a good commit message
-
Push to your fork
-
Wait for us, we will reply as soon as possible and if is the case we suggest some changes for a better quality of the code
-
Please, if you push more than one commit let's keep the history clean 😜
Thank you for your contribution! 🤝
If you wanna fix a bug:
-
Fork this project
-
Clone the repo with the following command:
git clone [email protected]:your-username/systemdy.git
-
Install dependencies with:
bin/setup
-
Make your changes
-
Write tests.
NOTE: For a correct testing procedure read our Note for testing
-
Make the tests pass with the following command:
rake spec
-
Add notes about your changes to the
CHANGELOG.md
file -
Write a good commit message
-
Push to your fork
-
Wait for us, we will reply as soon as possible and if is the case we suggest some changes for a better quality of the code
-
Please, if you push more than one commit let's keep the history clean 😜
Thank you for your contribution! 🤝
This gem was tested on a postgresql service.
For better testing install postgresql service on your system.
If you don't want to install it:
- go to spec/setup/test_variables.rb
and replace:
- let (:real_service_name) { 'postgresql' }
with a service already installed on your system as follows:
- let (:real_service_name) { 'a_service_already_installed_on_your_system' }
The gem is available as open source under the terms of the MIT License.
- An interesting article on how to run sudo commands without password
- The official Systemd documentation for time specification
- Thanks to @colstrom and his systemized for the great inspiration