- 0 Comments
- 1865 views
Welcome to CodeNameJessica
✨ Welcome to CodeNameJessica! ✨
💻 Where tech meets community.
Hello, Guest! 👋
You're just a few clicks away from joining an exclusive space for tech enthusiasts, problem-solvers, and lifelong learners like you.
🔐 Why Join?
By becoming a member of CodeNameJessica, you’ll get access to:
✅ In-depth discussions on Linux, Security, Server Administration, Programming, and more
✅ Exclusive resources, tools, and scripts for IT professionals
✅ A supportive community of like-minded individuals to share ideas, solve problems, and learn together
✅ Project showcases, guides, and tutorials from our members
✅ Personalized profiles and direct messaging to collaborate with other techies
🌐 Sign Up Now and Unlock Full Access!
As a guest, you're seeing just a glimpse of what we offer. Don't miss out on the complete experience! Create a free account today and start exploring everything CodeNameJessica has to offer.
CodeName Blogs
Featured Entries
- 0 Comments
- 1203 views
- 0 Comments
- 1146 views
- 0 Comments
- 1255 views
- 0 Comments
- 406 views
Our community blogs
-
by: Abhishek Prakash
Thu, 03 Jul 2025 05:13:51 GMT
And we achieved the goal of 75 new lifetime members. Thank you for that 🙏🙏
I think I have activated it for everyone, even for members who didn't explicitly notify me after the payment. But if anyone is still left out, just send me an email.
By the way, all the logged-in Plus members can download the 'Linux for DevOps' eBook from this page. I'll be adding a couple of more ebooks (created and extended from existing content) for the Plus members.
💬 Let's see what else you get in this edition
- Bcachefs running into trouble.
- A new Rust-based GPU driver.
- Google giving the Linux Foundation a gift.
- And other Linux news, tips, and, of course, memes!
📰 Linux and Open Source News
- digiKam 8.7 is here with many upgrades.
- Tyr is a new Rust-based driver for Arm Mali GPUs.
- Claudia is an open source GUI solution for Claude AI coding.
- Broadcom has been bullying enterprises with VMware audits.
- Google has donated the A2A protocol to the Linux foundation.
- Murena Fairphone (Gen. 6) has been introduced with some decent specs.
- Warp 2.0 is here with AI agents, better terminal tools, and more.
- Cloudflare has released Orange Me2eets, an E2EE video calling solution.
- Bazzite was looking at a grim future. Luckily, the proposal to retire 32-bit support on Fedora has been dropped, for now.
🧠 What We’re Thinking About
A new Linux kernel drama has unfolded, this time, it's Bcachefs.
New Linux Kernel Drama: Torvalds Drops Bcachefs Support After ClashThings have taken a bad turn for Bcachefs as Linux supremo Linus Torvalds is not happy with their objections.When you are done with that, you can go through LibreOffice's technical dive of the ODF file format.
🧮 Linux Tips, Tutorials and More
- There are some superb privacy-focused Notion alternatives out there.
- Learn a thing or two about monitoring CPU and GPU temperatures in your Linux system.
- Although commands like inxi are there, this GUI tool gives you an easy way to list the hardware configuration of your computer in Linux.
- Similarly, there are plenty of CLI tools for system monitoring, but you also have GUI-based task managers.
Relive the nostalgia with these tools to get a retro vibe on Linux.
Relive the Golden Era: 5 Tools to Get Retro Feel on LinuxGet retro vibe on Linux with these tools.Desktop Linux is mostly neglected by the industry but loved by the community. For the past 13 years, It's FOSS has been helping people use Linux on their personal computers. And we are now facing the existential threat from AI models stealing our content.
If you like what we do and would love to support our work, please become It's FOSS Plus member. It costs $24 a year (less than the cost of a burger meal each month) and you get an ad-free reading experience with the satisfaction of helping the desktop Linux community.
👷 Homelab and Hardware Corner
I have received the Pironman Max case for review and have assembled it too. I am looking forward to having a RAID setup for fun on it. I'll keep you posted if I made it or not 😄
Pironman 5-Max: The Best Raspberry Pi 5 Case Just Got UpgradedAnd the first 500 get a 25% pre-order discount offer. So hurry up with the purchase.✨ Project Highlight
AnduinOS is in the spotlight lately, have you checked it out?
A New Linux Distro Has Set Out To Look Like Windows 11: I Try AnduinOS!We take a brief look at AnduinOS, trying to mimic the Windows 11 look. Is it worth it?📽️ Videos I am Creating for You
See a better top in action in the latest video.
🧩 Quiz Time
This quiz will test your knowledge of Apt.
Apt Command QuizDebian or Ubuntu user? This is the apt quiz for you. Pun intended, of course :)💡 Quick Handy Tip
The Dolphin file manager offers you a selection mode. To activate it, press the
Space bar
.In this view, you can single click on a file/folder to select them. Here, you will notice that a quick access bar appears at the bottom when you select items, offering actions like Copy, Cut, Rename, Move to Trash, etc.
🤣 Meme of the Week
🗓️ Tech Trivia
The IBM 650, introduced on July 2, 1953, was one of the first widely used computers, featuring a magnetic drum for storage and using punch cards for programming. With a memory capacity of 20,000 decimal digits, it became a workhorse for businesses and universities throughout the 1950s.
🧑🤝🧑 FOSSverse Corner
Canonical is making some serious bank, and our FOSSers have noticed.
Ubuntu Maker Canonical Generated Nearly $300M In Revenue Last YearHow do they do this sum, its not from the desktop free version, can only guess its server technology❤️ With love
Please share it with your Linux-using friends and encourage them to subscribe (hint: it's here).
Share the articles in Linux Subreddits and community forums.
Follow us on Google News and stay updated in your News feed.
Opt for It's FOSS Plus membership and support us 🙏
Enjoy FOSS 😄
Recent Entries
-
Latest entry by Blogger,
By: Edwin
Wed, 30 Apr 2025 13:08:34 +0000A lot of people want Linux but do not want to go either remove Windows or take up the overwhelming task of dual booting. For those people, WSL (Windows Subsystem for Linux) came as a blessing. WSL lets you run Linux on your Windows device without the overhead of a Virtual Machine (VM). But in some cases where you want to fix a problem or simply do not want WSL anymore, you may have to uninstall WSL from your Windows system.
Here is step-by-step guide to remove WSL from your Windows system, remove any Linux distribution, delete all related files, and clear up some disk space. Ready? Get. Set. Learn!
What is WSL
You probably knew by now that we will always start with the basics i.e., what WSL does. Think of WSL as a compatibility layer for running Linux binaries on Microsoft Windows systems. It comes in two versions:
- WSL 1: Uses a translation layer between Linux and Windows.
- WSL 2: Uses a real Linux kernel in a lightweight VM.
All around the world, WSL is a favourite among developers, system administrators, and students for running Linux tools like bash, ssh, grep, awk, and even Docker. But if you have moved to a proper Linux system or just want to do a clean reinstall, here are the instructions to remove WSL completely without any errors.
Step 1: How to Uninstall Linux Distributions
The first step to uninstall WSL completely is to remove all installed Linux distributions.
Check Installed Distros
To check for the installed Linux distributions, open PowerShell or Command Prompt and run the command:
wsl --list --all
After executing this command, you will see a list of installed distros, such as:
- Ubuntu
- Debian
- Kali
- Alpine
How to Uninstall a Linux Distro
To uninstall a distro like Ubuntu, follow these instructions:
- Press Windows key + I to open Settings window.
- Go to Apps, then click Installed Apps (or Apps & Features).
- Search for your distro and click Uninstall.
Repeat for all distros you no longer need. If you plan to uninstall WSL completely, we recommend removing all distros.
if you prefer PowerShell, run these commands
wsl --unregister <DistroName>
For example, if you want to remove Ubuntu, execute the command:
wsl --unregister Ubuntu
This removes the Linux distro and all its associated files.
Step 2: Uninstall WSL Components
Once we have removed the unwanted distros, let us uninstall the WSL platform itself.
- Open Control Panel and navigate to Programs and then click Turn Windows features on or off.
- Uncheck these boxes:
- Windows Subsystem for Linux
- Virtual Machine Platform (used by WSL 2)
- Windows Hypervisor Platform (optional)
- Click OK and restart your system.
Step 3: Remove WSL Files and Cache
Even after uninstalling WSL and Linux distributions, some data might remain. Here are the instructions to delete WSL’s cached files and reclaim disk space.
To delete the WSL Folder, open File Explorer and go to:
%USERPROFILE%\AppData\Local\Packages
Look for folders like:
- CanonicalGroupLimited…Ubuntu
- Debian…
- KaliLinux…
Delete any folders related to WSL distros you removed.
Step 4: Remove WSL CLI Tool (Optional)
If you installed WSL using the Microsoft Store (i.e., “wsl.exe” package), you can also uninstall it directly from the Installed Apps section:
- Go to Settings, and then to Apps and then open Installed Apps.
- Search for Windows Subsystem for Linux.
- Click Uninstall.
Step 5: Clean Up with Disk Cleanup Tool
Finally, use the built-in Disk Cleanup utility to clear any temporary files.
- Press “Windows key + S and search for Disk Cleanup.
- Choose your system drive (usually drive C:).
- Select options like:
- Temporary files
- System created Windows error reporting
- Delivery optimization files
- Click OK to clean up.
Bonus Section: How to Reinstall WSL (Optional)
If you are removing WSL due to issues or conflicts, you can always do a fresh reinstall.
Here is how you can install latest version of WSL via PowerShell
wsl --install
This installs WSL 2 by default, along with Ubuntu.
Wrapping Up
Uninstalling WSL may sound tricky, but by following these steps, you can completely remove Linux distributions, WSL components, and unwanted files from your system. Whether you are making space for something new or just doing some digital spring cleaning, this guide ensures that WSL is uninstalled safely and cleanly.
If you ever want to come back to the Linux world, WSL can be reinstalled with a single command, which we have covered as a precaution. Let us know if you face any errors. Happy learning!
The post Uninstall WSL: Step-by-Step Simple Guide appeared first on Unixmen.
Recent Entries
-
Latest entry by Blogger,
by: Patrick Brosset
Tue, 01 Jul 2025 12:42:38 +0000Four years ago, I wrote an article titled Minding the “gap”, where I talked about the CSS
gap
property, where it applied, and how it worked with various CSS layouts.At the time, I described how easy it was to evenly space items out in a flex, grid, or multi-column layout, by using the
gap
property. But, I also said that styling the gap areas was much harder, and I shared a workaround.However, workarounds like using extra HTML elements, pseudo-elements, or borders to draw separator lines tend to come with drawbacks, especially those that impact your layout size, interfere with assistive technologies, or pollute your markup with style-only elements.
Today, I’m writing again about layout gaps, but this time, to tell you all about a new and exciting CSS feature that’s going to change it all. What you previously had to use workarounds for, you’ll soon be able to do with just a few simple CSS properties that make it easy, yet also flexible, to display styled separators between your layout items.
There’s already a specification draft for the feature you can peruse. At the time I’m writing this, it is available in Chrome and Edge 139 behind a flag. But I believe it won’t be long before we turn that flag on. I believe other browsers are also very receptive and engaged.
Displaying decorative lines between items of a layout can make a big difference. When used well, these lines can bring more structure to your layout, and give your users more of a sense of how the different regions of a page are organized.
Introducing CSS gap decorations
If you’ve ever used a multi-column layout, such as by using the
column-width
property, then you might already be familiar with gap decorations. You can draw vertical lines between the columns of a multi-column layout by using thecolumn-rule
property:article { column-width: 20rem; column-rule: 1px solid black; }
The CSS gap decorations feature builds on this to provide a more comprehensive system that makes it easy for you to draw separator lines in other layout types.
For example, the draft specification says that the
column-rule
property also works in flexbox and grid layouts:.my-grid-container { display: grid; gap: 2px; column-rule: 2px solid pink; }
No need for extra elements or borders! The key benefit here is that the decoration happens in CSS only, where it belongs, with no impacts to your semantic markup.
The CSS gap decorations feature also introduces a new
row-rule
property for drawing lines between rows:.my-flex-container { display: flex; gap: 10px; row-rule: 10px dotted limegreen; column-rule: 5px dashed coral; }
But that’s not all, because the above syntax also allows you to define multiple, comma-separated, line style values, and use the same
repeat()
function that CSS grid already uses for row and column templates. This makes it possible to define different styles of line decorations in a single layout, and adapt to an unknown number of gaps:.my-container { display: grid; gap: 2px; row-rule: repeat(2, 1px dashed red), 2px solid black, repeat(auto, 1px dotted green); }
Finally, the CSS gap decorations feature comes with additional CSS properties such as
row-rule-break
,column-rule-break
,row-rule-outset
,column-rule-outset
, andgap-rule-paint-order
, which make it possible to precisely customize the way the separators are drawn, whether they overlap, or where they start and end.And of course, all of this works across grid, flexbox, multi-column, and soon, masonry!
Browser support
Currently, the CSS gap decorations feature is only available in Chromium-based browsers.
The feature is still early in the making, and there’s time for you all to try it and to provide feedback that could help make the feature better and more adapted to your needs.
If you want to try the feature today, make sure to use Edge or Chrome, starting with version 139 (or another Chromium-based browser that matches those versions), and enable the flag by following these steps:
- In Chrome or Edge, go to
about://flags
. - In the search field, search for Enable Experimental Web Platform Features.
- Enable the flag.
- Restart the browser.
To put this all into practice, let’s walk through an example together that uses the new CSS gap decorations feature. I also have a final example you can demo.
Using CSS gap decorations
Let’s build a simple web page to learn how to use the feature. Here is what we’ll be building:
The above layout contains a header section with a title, a navigation menu with a few links, a main section with a series of short paragraphs of text and photos, and a footer.
We’ll use the following markup:
<body> <header> <h1>My personal site</h1> </header> <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">Blog</a></li> <li><a href="#">About</a></li> <li><a href="#">Links</a></li> </ul> </nav> <main> <article> <p>...</p> </article> <article> <img src="cat.jpg" alt="A sleeping cat."> </article> <article> <p>...</p> </article> <article> <img src="tree.jpg" alt="An old olive tree trunk."> </article> <article> <p>...</p> </article> <article> <p>...</p> </article> <article> <p>...</p> </article> <article> <img src="strings.jpg" alt="Snow flakes falling in a motion blur effect."> </article> </main> <footer> <p>© 2025 Patrick Brosset</p> </footer> </body>
We’ll start by making the
<body>
element be a grid container. This way, we can space out the<header>
,<nav>
,<main>
, and<footer>
elements apart in one go by using thegap
property:body { display: grid; gap: 4rem; margin: 2rem; }
Let’s now use the CSS gap decorations feature to display horizontal separator lines within the gaps we just defined:
body { display: grid; gap: 4rem; margin: 2rem; row-rule: 1rem solid #efefef; }
This gives us the following result:
We can do a bit better by making the first horizontal line look different than the other two lines, and simplify the
row-rule
value by using therepeat()
syntax:body { display: grid; gap: 4rem; margin: 2rem; row-rule: 1rem solid #efefef, repeat(2, 2px solid #efefef); }
With this new
row-rule
property value, we’re telling the browser to draw the first horizontal separator as a1rem
thick line, and the next two separators as2px
thick lines, which gives the following result:Now, let’s turn our attention to the navigation element and its list of links. We’ll use flexbox to display the links in a single row, where each link is separated from the other links by a gap and a vertical line:
nav ul { display: flex; flex-wrap: wrap; gap: 2rem; column-rule: 2px dashed #666; }
Very similarly to how we used the
row-rule
property before, we’re now using thecolumn-rule
property to display a dashed2px
thick separator between the links.Our example web page now looks like this:
The last thing we need to change is the
<main>
element and its paragraphs and pictures. We’ll use flexbox again and display the various children in a wrapping row of varying width items:main { display: flex; flex-wrap: wrap; gap: 4rem; } main > * { flex: 1 1 200px; } main article:has(p) { flex-basis: 400px; }
In the above code snippet, we’re setting the
<main>
element to be a wrapping flex container with a4rem
gap between items and flex lines. We’re also making the items have a flex basis size of200px
for pictures and400px
for text, and allowing them to grow and shrink as needed. This gives us the following result:Let’s use CSS gap decorations to bring a little more structure to our layout by drawing
2px
thick separator lines between the rows and columns of the layout:main { display: flex; flex-wrap: wrap; gap: 4rem; row-rule: 2px solid #999; column-rule: 2px solid #999; }
This gives us the following result, which is very close to our expected design:
The last detail we want to change is related to the vertical lines. We don’t want them to span across the entire height of the flex lines but instead start and stop where the content starts and stops.
With CSS gap decorations, we can easily achieve this by using the
column-rule-outset
property to fine-tune exactly where the decorations start and end, relative to the gap area:main { display: flex; flex-wrap: wrap; gap: 4rem; row-rule: 2px solid #999; column-rule: 2px solid #999; column-rule-outset: 0; }
The
column-rule-outset
property above makes the vertical column separators span the height of each row, excluding the gap area, which is what we want:And with that, we’re done with our example. Check out the live example, and source code.
Learn more
There’s more to the feature and I mentioned a couple more CSS properties earlier
gap-rule-paint-order
, which lets you control which of the decorations, rows or columns, appear above the other ones.row-rule-break
/column-rule-break
, which sets the behavior of the decoration lines at intersections. In particular, whether they are made of multiple segments, which start and end at intersections, or single, continuous lines.
Because the feature is new, there isn’t MDN documentation about it yet. So to learn more, check out:
- CSS Gap Decorations Module Level 1 (First Public Working Draft)
- Microsoft Edge Explainer
The Edge team has also created an interactive playground where you can use visual controls to configure gap decorations.
And, of course, the reason this is all implemented behind a flag is to elicit feedback from developers like you! If you have any feedback, questions, or bugs about this feature, I definitely encourage you to open a new ticket on the Chromium issue tracker.
The Gap Strikes Back: Now Stylable originally published on CSS-Tricks, which is part of the DigitalOcean family. You should get the newsletter.
Recent Entries
- In Chrome or Edge, go to
-
SaltStack (SALT): A Comprehensive Overview
SaltStack, commonly referred to as SALT, is a powerful open-source infrastructure management platform designed for scalability. Leveraging event-driven workflows, SALT provides an adaptable solution for automating configuration management, remote execution, and orchestration across diverse infrastructures.
This document offers an in-depth guide to SALT for both technical teams and business stakeholders, demystifying its features and applications.
What is SALT?
SALT is a versatile tool that serves multiple purposes in infrastructure management:
Configuration Management Tool (like Ansible, Puppet, Chef): Automates the setup and maintenance of servers and applications.
Remote Execution Engine (similar to Fabric or SSH): Executes commands on systems remotely, whether targeting a single node or thousands.
State Enforcement System: Ensures systems maintain desired configurations over time.
Event-Driven Automation Platform: Detects system changes and triggers actions in real-time.
Key Technologies:
YAML: Used for defining states and configurations in a human-readable format.
Jinja: Enables dynamic templating for YAML files.
Python: Provides extensibility through custom modules and scripts.
Supported Architectures
SALT accommodates various architectures to suit organizational needs:
Master/Minion: A centralized control model where a Salt Master manages Salt Minions to send commands and execute tasks.
Masterless: A decentralized approach using
salt-ssh
to execute tasks locally without requiring a master node.
Core Components of SALT
Component
Description
Salt Master
Central control node that manages minions, sends commands, and orchestrates infrastructure tasks.
Salt Minion
Agent installed on managed nodes that executes commands from the master.
Salt States
Declarative YAML configuration files that define desired system states (e.g., package installations).
Grains
Static metadata about a system (e.g., OS version, IP address), useful for targeting specific nodes.
Pillars
Secure, per-minion data storage for secrets and configuration details.
Runners
Python modules executed on the master to perform complex orchestration tasks.
Reactors
Event listeners that trigger actions in response to system events.
Beacons
Minion-side watchers that emit events based on system changes (e.g., file changes or CPU spikes).
Key Features of SALT
Feature
Description
Agent or Agentless
SALT can operate in agent (minion-based) or agentless (masterless) mode.
Scalability
Capable of managing tens of thousands of nodes efficiently.
Event-Driven
Reacts to real-time system changes via beacons and reactors, enabling automation at scale.
Python Extensibility
Developers can extend modules or create custom ones using Python.
Secure
Employs ZeroMQ for communication and AES encryption for data security.
Role-Based Config
Dynamically applies configurations based on server roles using grains metadata.
Granular Targeting
Targets systems using name, grains, regex, or compound filters for precise management.
Common Use Cases
SALT is widely used across industries for tasks like:
Provisioning new systems and applying base configurations.
Enforcing security policies and managing firewall rules.
Installing and enabling software packages (e.g., HTTPD, Nginx).
Scheduling and automating patching across multiple environments.
Monitoring logs and system states with automatic remediation for issues.
Managing VM and container lifecycles (e.g., Docker, LXC).
Real-World Examples
Remote Command Execution:
salt '*' test.ping
(Pings all connected systems).salt 'web*' cmd.run 'systemctl restart nginx'
(Restarts Nginx service on all web servers).
State File Example (YAML):
nginx: pkg.installed: [] service.running: - enable: True - require: - pkg: nginx
Comparing SALT to Other Tools
Feature
Salt
Ansible
Puppet
Chef
Language
YAML + Python
YAML + Jinja
Puppet DSL
Ruby DSL
Agent Required
Optional
No
Yes
Yes
Push/Pull
Both
Push
Pull
Pull
Speed
Very Fast
Medium
Medium
Medium
Scalability
High
Medium-High
Medium
Medium
Event-Driven
Yes
No
No
Limited
Security Considerations
SALT ensures secure communication and authentication:
Authentication: Uses public/private key pairs to authenticate minions.
Encryption: Communicates via ZeroMQ encrypted with AES.
Access Control: Defines granular controls using Access Control Lists (ACLs) in the Salt Master configuration.
Additional Information
For organizations seeking enhanced usability, SaltStack Config offers a graphical interface to streamline workflow management. Additionally, SALT's integration with VMware Tanzu provides advanced automation for enterprise systems.
Installation Example
On a master node (e.g., RedHat):
sudo yum install salt-master
On minion nodes:
sudo yum install salt-minion
Configure
/etc/salt/minion
with:master: your-master-hostname
Then start the minion:
sudo systemctl enable --now salt-minion
Accept the minion on the master:
sudo salt-key -L # list all keys sudo salt-key -A # accept all pending minion keys
Where to Go Next
Git-based states with gitfs
Masterless setups for container deployments
Custom modules in Python
Event-driven orchestration with beacons + reactors
Large 600+ Server Patching in 3 Regions with 3 different Environments Example
Let give an example of have 3 different environments DEV (Development), PREP (Preproduction), and PROD (Production), now let's dig a little deeper and say we have 3 different regions EUS (East US), WUS (West US), and EUR (European) and we would like these patches to be applied on changing dates, such as DEV will be patched on 3 days after the second Tuesday, PREP will be patched on 5 days after the second Tuesday, and PROD will be 5 days after the 3rd Tuesday. The final clause to this mass configuration is, we would like the patches to be applied on the Client Local Time.
In many configurations such as AUM, or JetPatch, you would need several different Maintenace Schedules or plans to create this setup. With SALT, the configuration lies inside the minion, so configuration is much more defined, and simple to manage.
Use Case Recap
You want to patch three environment groups based on local time and specific schedules:
Environment
Schedule Rule
Timezone
Dev
3rd day after 2nd Tuesday of the month
Local
PREP
5th day after 2nd Tuesday of the month
Local
Prod
5th day after 3rd Tuesday of the month
Local
Each server knows its environment via Salt grains, and the local timezone via OS or
timedatectl
.Step-by-Step Plan
Set Custom Grains for Environment & Region
Create a Python script (run daily) that:
Checks if today matches the schedule per group
If yes, uses Salt to target minions with the correct grain and run patching
Schedule this script via cron or Salt scheduler
Use Salt States to define patching
Step 1: Define Custom Grains
On each minion, configure
/etc/salt/minion.d/env_grains.conf
:grains: environment: dev # or prep, prod region: us-east # or us-west, eu-central, etc.
Then restart the minion:
sudo systemctl restart salt-minion
Verify:
salt '*' grains.items
Step 2: Salt State for Patching
Create
patching/init.sls
:update-packages: pkg.uptodate: - refresh: True - retry: attempts: 3 interval: 15 reboot-if-needed: module.run: - name: system.reboot - onlyif: 'test -f /var/run/reboot-required'
Step 3: Python Script to Orchestrate Patching
Let’s build
run_patching.py
. It:Figures out the correct date for patching
Uses
salt
CLI to run patching for each groupHandles each group in its region and timezone
#!/usr/bin/env python3 import subprocess import datetime import pytz from dateutil.relativedelta import relativedelta, TU # Define your environments and their rules envs = { "dev": {"offset": 3, "week": 2}, "prep": {"offset": 5, "week": 2}, "prod": {"offset": 5, "week": 3} } # Map environments to regions (optional) regions = { "dev": ["us-east", "us-west"], "prep": ["us-east", "eu-central"], "prod": ["us-east", "us-west", "eu-central"] } # Timezones per region region_tz = { "us-east": "America/New_York", "us-west": "America/Los_Angeles", "eu-central": "Europe/Berlin" } def calculate_patch_date(year, month, week, offset): second_tuesday = datetime.date(year, month, 1) + relativedelta(weekday=TU(week)) return second_tuesday + datetime.timedelta(days=offset) def is_today_patch_day(env, region): now = datetime.datetime.now(pytz.timezone(region_tz[region])) target_day = calculate_patch_date(now.year, now.month, envs[env]["week"], envs[env]["offset"]) return now.date() == target_day and now.hour >= desired_hour def run_salt_target(environment, region): target = f"environment:{environment} and region:{region}" print(f"Patching {target}...") subprocess.run([ "salt", "-C", target, "state.apply", "patching" ]) def main(): for env in envs: for region in regions[env]: if is_today_patch_day(env, region): run_salt_target(env, region) if __name__ == "__main__": main()
Make it executable:
chmod +x /srv/scripts/run_patching.py
Test it:
./run_patching.py
Step 4: Schedule via Cron (on Master)
Edit crontab:
crontab -e
Add daily job:
# Run daily at 6 AM UTC 0 6 * * * /srv/scripts/run_patching.py >> /var/log/salt/patching.log 2>&1
This assumes the local time logic is handled in the script using each region’s timezone.
Security & Safety Tips
Test patching states on a few dev nodes first (
salt -G 'environment:dev' -l debug state.apply patching
)Add Slack/email notifications (Salt Reactor or Python
smtplib
)Consider dry-run support with
test=True
(inpkg.uptodate
)Use
salt-run jobs.list_jobs
to track job execution
Optional Enhancements
Use Salt Beacons + Reactors to monitor and patch in real-time
Integrate with JetPatch or Ansible for hybrid control
Add patch deferral logic for critical services
Write to a central patching log DB with job status per host
Overall Architecture
Minions:
Monitor the date/time via beacons
On patch day (based on local logic), send a custom event to the master
Master:
Reacts to that event via a reactor
Targets the sending minion and applies the
patching
state
Step-by-Step: Salt Beacon + Reactor Model
1. Define a Beacon on Each Minion
File:
/etc/salt/minion.d/patchday_beacon.conf
beacons: patchday: interval: 3600 # check every hour
This refers to a custom beacon we will define.
2. Create the Custom Beacon (on all minions)
File:
/srv/salt/_beacons/patchday.py
import datetime from dateutil.relativedelta import relativedelta, TU import pytz __virtualname__ = 'patchday' def beacon(config): ret = [] grains = __grains__ env = grains.get('environment', 'unknown') region = grains.get('region', 'unknown') # Define rules rules = { "dev": {"offset": 3, "week": 2}, "prep": {"offset": 5, "week": 2}, "prod": {"offset": 5, "week": 3} } region_tz = { "us-east": "America/New_York", "us-west": "America/Los_Angeles", "eu-central": "Europe/Berlin" } if env not in rules or region not in region_tz: return ret # invalid or missing config tz = pytz.timezone(region_tz[region]) now = datetime.datetime.now(tz) rule = rules[env] patch_day = (datetime.date(now.year, now.month, 1) + relativedelta(weekday=TU(rule["week"])) + datetime.timedelta(days=rule["offset"])) if now.date() == patch_day: ret.append({ "tag": "patch/ready", "env": env, "region": region, "datetime": now.isoformat() }) return ret
3. Sync Custom Beacon to Minions
On the master:
salt '*' saltutil.sync_beacons
Enable it:
salt '*' beacons.add patchday '{"interval": 3600}'
4. Define Reactor on the Master
File:
/etc/salt/master.d/reactor.conf
reactor: - 'patch/ready': - /srv/reactor/start_patch.sls
5. Create Reactor SLS File
File:
/srv/reactor/start_patch.sls
{% set minion_id = data['id'] %} run_patching: local.state.apply: - tgt: {{ minion_id }} - arg: - patching
This reacts to
patch/ready
event and applies thepatching
state to the calling minion.6. Testing the Full Flow
Restart the minion:
systemctl restart salt-minion
Confirm the beacon is registered:
salt '*' beacons.list
Trigger a manual test (simulate patch day by modifying date logic)
Watch events on master:
salt-run state.event pretty=True
Confirm patching applied:
salt '*' saltutil.running
7. Example:
patching/init.sls
Already shared, but here it is again for completeness:
update-packages: pkg.uptodate: - refresh: True - retry: attempts: 3 interval: 15 reboot-if-needed: module.run: - name: system.reboot - onlyif: 'test -f /var/run/reboot-required'
Benefits of This Model
Real-time and event-driven – no need for polling or external scripts
Timezone-aware, thanks to local beacon logic
Self-healing – minions signal readiness independently
Audit trail – each event is logged in Salt’s event bus
Extensible – you can easily add Slack/email alerts via additional reactors
Goal
Track patching event completions per minion
Store patch event metadata: who patched, when, result, OS, IP, environment, region, etc.
Generate readable reports in:
CSV/Excel
HTML dashboard
JSON for API or SIEM ingestion
Step 1: Customize Reactor to Log Completion
Let’s log each successful patch into a central log file or database (like SQLite or MariaDB).
Update Reactor:
/srv/reactor/start_patch.sls
Add a returner to store job status.
{% set minion_id = data['id'] %} run_patching: local.state.apply: - tgt: {{ minion_id }} - arg: - patching - kwarg: returner: local_json # You can also use 'mysql', 'elasticsearch', etc.
Configure Returner (e.g.,
local_json
)In
/etc/salt/master
:returner_dirs: - /srv/salt/returners ext_returners: local_json: file: /var/log/salt/patch_report.json
Or use a MySQL returner:
mysql.host: 'localhost' mysql.user: 'salt' mysql.pass: 'yourpassword' mysql.db: 'salt' mysql.port: 3306
Enable returners:
salt-run saltutil.sync_returners
Step 2: Normalize Patch Data (Optional Post-Processor)
If using JSON log, create a post-processing script to build reports:
process_patch_log.py
import json import csv from datetime import datetime def load_events(log_file): with open(log_file, 'r') as f: return [json.loads(line) for line in f if line.strip()] def export_csv(events, out_file): with open(out_file, 'w', newline='') as f: writer = csv.DictWriter(f, fieldnames=[ 'minion', 'date', 'environment', 'region', 'result' ]) writer.writeheader() for e in events: writer.writerow({ 'minion': e['id'], 'date': datetime.fromtimestamp(e['_stamp']).isoformat(), 'environment': e['return'].get('grains', {}).get('environment', 'unknown'), 'region': e['return'].get('grains', {}).get('region', 'unknown'), 'result': 'success' if e['success'] else 'failure' }) events = load_events('/var/log/salt/patch_report.json') export_csv(events, '/srv/reports/patching_report.csv')
Step 3: Build a Simple Web Dashboard
If you want to display reports via a browser:
🛠 Tools:
Flask or FastAPI
Bootstrap or Chart.js
Reads JSON/CSV and renders:
Example Chart Dashboard Features:
✅ Last patch date per server
📍 Patching success rate per region/env
🔴 Highlight failed patching
📆 Monthly compliance timeline
Would you like a working example of that Flask dashboard? I can include the full codebase if so.
Step 4: Send Reports via Email (Optional)
🐍 Python:
send_report_email.py
import smtplib from email.message import EmailMessage msg = EmailMessage() msg["Subject"] = "Monthly Patch Report" msg["From"] = "patchbot@example.com" msg["To"] = "it-lead@example.com" msg.set_content("Attached is the patch compliance report.") with open("/srv/reports/patching_report.csv", "rb") as f: msg.add_attachment(f.read(), maintype="text", subtype="csv", filename="patching_report.csv") with smtplib.SMTP("localhost") as s: s.send_message(msg)
Schedule that weekly or monthly with
cron
.Flask Dashboard (Patch Reporting)
app.py
from flask import Flask, render_template import csv from collections import defaultdict app = Flask(__name__) @app.route('/') def index(): results = [] success_count = defaultdict(int) fail_count = defaultdict(int) with open('/srv/reports/patching_report.csv', 'r') as f: reader = csv.DictReader(f) for row in reader: results.append(row) key = f"{row['environment']} - {row['region']}" if row['result'] == 'success': success_count[key] += 1 else: fail_count[key] += 1 summary = [ {"group": k, "success": success_count[k], "fail": fail_count[k]} for k in sorted(set(success_count) | set(fail_count)) ] return render_template('dashboard.html', results=results, summary=summary) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0', port=5000)
templates/dashboard.html
<!DOCTYPE html> <html> <head> <title>Patch Compliance Dashboard</title> <style> body { font-family: Arial; padding: 20px; } table { border-collapse: collapse; width: 100%; margin-bottom: 30px; } th, td { border: 1px solid #ccc; padding: 8px; text-align: left; } th { background-color: #f4f4f4; } .fail { background-color: #fdd; } .success { background-color: #dfd; } </style> </head> <body> <h1>Patch Compliance Dashboard</h1> <h2>Summary</h2> <table> <tr><th>Group</th><th>Success</th><th>Failure</th></tr> {% for row in summary %} <tr> <td>{{ row.group }}</td> <td>{{ row.success }}</td> <td>{{ row.fail }}</td> </tr> {% endfor %} </table> <h2>Detailed Results</h2> <table> <tr><th>Minion</th><th>Date</th><th>Environment</th><th>Region</th><th>Result</th></tr> {% for row in results %} <tr class="{{ row.result }}"> <td>{{ row.minion }}</td> <td>{{ row.date }}</td> <td>{{ row.environment }}</td> <td>{{ row.region }}</td> <td>{{ row.result }}</td> </tr> {% endfor %} </table> </body> </html>
How to Use
pip install flask python app.py
Then visit
http://localhost:5000
or your server’s IP at port 5000.Optional: SIEM/Event Forwarding
If you use Elasticsearch, Splunk, or Mezmo:
Use a returner like
es_return
,splunk_return
, or send via custom script using REST API.Normalize fields: hostname, env, os, patch time, result
Filter dashboards by compliance groupings
TL;DR: Reporting Components Checklist
Component
Purpose
Tool
JSON/DB logging
Track patch status
Returners
Post-processing script
Normalize data for business
Python
CSV/Excel export
Shareable report format
Python
csv
moduleHTML dashboard
Visualize trends/compliance
Flask, Chart.js, Bootstrap
Email automation
Notify stakeholders
smtplib
, cronSIEM/Splunk integration
Enterprise log ingestion
REST API or native returners
Recent Entries
-
by: Abhishek Prakash
Fri, 27 Jun 2025 18:29:17 +0530We have converted our text-based Docker course into an eBook; Learn Docker Quickly.
It is available for free to LHB Pro members along with all the other eBooks in the resources section.
If you are not a Pro member, you can either opt for the Pro membership or purchase just this ebook from our Gumroad page.
I am working on the next series and hopefully, you'll see it in July. Stay tuned 😄
Recent Entries
-
No blog entries yet