Sharing a tmux Session in Read-Only Mode for Training

During hands-on Linux training it is useful to let a trainee follow your terminal session live — without the risk of his accidentally typing something that derails the demo. tmux makes this straightforward through shared sockets and its built-in read-only attach mode.

The problem

When demonstrating something in a terminal, a trainee sitting next to you or connected over SSH can share your screen, but they have no keyboard control over what they see.

[Read More]

WarmDesk now has a website

The WarmDesk project now has a proper website.

You can find it at https://tonk.github.io/warmdesk/ where you can read about all the features, browse the documentation, and find installation instructions.

The site covers everything from a quick start to a full administrator guide, including database setup, reverse proxy configuration, and horizontal scaling with Redis.

The source of WarmDesk itself is, as always, on GitHub at https://github.com/tonk/warmdesk.

WarmDesk - Self-Hosted Project Management

Modern software teams produce a constant stream of tasks, conversations, customer commitments, and billable hours. Most commercial tools that manage all of this run in somebody else’s cloud, lock data inside proprietary formats, and charge per seat. WarmDesk is a self-hosted alternative: a single binary that covers Kanban boards, Scrum sprints, team chat, discussion threads, customer contracts, and time tracking — owned and operated by you.

What is WarmDesk?

WarmDesk is a project management platform built specifically for teams that require control over their own data. It ships as a single statically-linked Go binary that contains the REST API, the WebSocket hub, a built-in file server, and a bundled Vue 3 single-page application.

[Read More]

WarmDesk collection released

As you probably know, I’m completely addicted to Ansible, so my new project requires some Ansible love.

As I have set it up with an API that can do, almost, anything with the cards, it was a breeze to create an Ansible collection to manage the WarmDesk instance.

I have created a collection from all the modules and uploaded that to the Galaxy. https://galaxy.ansible.com/ui/repo/published/ansilabnl/warmdesk/

You can install it with

ansible-galaxy collection install ansilabnl.warmdesk
[Read More]

Project Coworker renamed to WarmDesk

As I was typing along in my quest for success with Coworker, I noticed that the name was already used by multiple projects, so it was not wise to keep using this name. I really want to avoid name conflicts.

Asking Claude to come up with a new name, resulted in a lot of nice names, all where already taken.

Then the name WarmDesk came up. This is a warm environment, with a nice cup of coffee. And all the tickets and Kanban stuff on the desk.

[Read More]

Building an app using only AI

I do quite a lot of development work for a customer, and this particular customer uses Ryver (https://ryver.com) for the management of the different projects. This works rather well and it’s not very expensive. But a big problem is that it looks like development of Ryver is completely shutdown. At least the last couple of years nothing has happened, nothing at all.

As Marcel (my Boss Mann) was pushing me to use Claude as a development aid, I got curious if Claude could give me a hand. I even went a step further and decided to go the very lazy route. I don’t want to write a single line of code.

[Read More]

Cleaning old hosts from AAP

Using Ansible Automation Platform is very handy to run Ansible playbooks in an orderly way. And Red Hat even offers a developer license so that it’s possible to test all features of AAP.

But one problem that I ran into, is that I often throw away machines and start from scratch again. As the developer license allows for 16 machines, I thought I was on the save side, as I have a maximum of 4, maybe 5 machines I use for testing.

[Read More]

Remove an organization from Git

When I was busy with a late spring-cleaning, I thought it to be a good idea to remove some old repositories from my Git server.

At home I am running Forgejo and when I want to remove a complete organization, I need to click and type a lot.

But Forgejo, just as Gitea has a wonderful API, so, why not use that??

I saw this at Justyns site and I stole ^W borrowed this script.

[Read More]

The nginx webserver as HTTPS/SSL proxy

As CentOS 7 is getting to the end of it’s live it’s time to start thinking about an upgrade.

On my old server I tried LEAPP a couple of times (on a clone, of course), but success was not really guaranteed. So, a complete reinstall is in order.

But, as I move from CentOS 7 to Rocky Linux 9, this automatically means some packages are no longer available. I was using sslh to connect though SSH and HTTPS on port 443.

[Read More]

Ansible AWX demo environment

As I was planning an Ansible Meetup about the Ansible Automation Platform (AAP, the successor of Ansible Tower) I was contemplating about a demo environment for the attendants. This can be done with ease as it it nothing more than clicky-di-click.

You can imagine that’s not the way I went :-). There is a simple rule in life:
If you can automate it, automate it. The complete environment is going to be a multipart environment, so that the attendants can experiment and have an environment that slightly resembles real live.

[Read More]

Let the Cow say moo

When working for a customer I was installing an Ansible Automation Platform cluster and to keep track of all systems I decided to create a nice message of the day, of course with cowsay.

Something like this:

       ___________________________
      < Member of the AAP Cluster >      | Host name   : thunderbolt
       ---------------------------       | Host alias  : cn01
                  \   ^__^               | Function    : Ansible AAP Control node
                   \  (oo)\_______       | Location    : Amsterdam
                      (__)\       )\/\   | IP address  : 192.168.63.194
                          ||----w |      | VMware name : EXDTONKE01
                          ||     ||
[Read More]

Getting Ansible info into your playbook

Early this week a co-worker asked if it was possible to access the Ansible command-line in a playbook. It seems that is not the case, in a normal, clean Ansible environment.

But in the meantime I was creating a playbook that served multiple purposes, stopping and starting services. These playbooks are completely the same, except for the start and stop keywords. Of course I could have solved that with a variabele, either hardcoded or as an extra variable on the commandline. But, where is the fun in that :-)

[Read More]

Web Application Firewall and CRS

During my stay at CfgMgmtCamp I attended the presentation of Franziska Bühler (@bufrasch) titled Web Application Firewall - Friend of your DevOps pipeline?. She talked about Web Application Firewalls (WAF) and the Core Rule Set (CRS) for owasp

Being into security and stuff like that myself, I decided I wanted to try to get the web application with ModSecurity up and running in my own test environment.

My test environment consists of a CentOS8 machine with NGINX and it turned out to be a little trickier than I thought.

[Read More]

Ansible with multiple vault ID's

In our work environment we have role-based access for passwords (of course). But as we deploy all systems with Ansible, we could end up that someone with only deploy permission ends up with access to all passwords. It’s obvious that we don’t want that, so I started checking in to Ansible’s ability to have multiple vault passwords.

Ansible Vault IDs

Starting with Ansible 2.4 and above, vault IDs are supported.

[Read More]

Ansible with loops or lookup

Since Ansible version 2.5 there is a lot of discussion and confusion about the loop syntax. There is also discussion if with_…​: will be replaced by loop: deprecating the with_…​ keywords. Even Ansibles documentation is not clear about this.

Should I use loop: or with_…​:, in fact nobody really knows. What would the correct syntax be?

---
- name: Loops with with_ and lookup
  hosts: localhost
  connection: local
  gather_facts: no
  vars:
    people:
      - john
      - paul
      - mary
    drinks:
      - beer
      - wine
      - whisky

  tasks:
    - name: with nested
      debug:
        msg: "with_nested: item[0] is '{{ item[0] }}' and item[1] is '{{ item[1] }}'"
      with_nested:
        - "{{ people }}"
        - "{{ drinks }}"

    - name: nested and loop
      debug:
        msg: "nested_loop: item[0] is '{{ item[0] }}' and item[1] is '{{ item[1] }}'"
      loop:
        - "{{ people }}"
        - "{{ drinks }}"
[Read More]

Ansible: One Role to Rule them All

I am a long time Ansible user and contributor (since 2012) and I have been struggling with a decent setup for a multi-environment case. I have been designing and re-designing a lot, until I came up with this design. And what a coincidence, a customer wanted a setup that was exactly this. So this concept is a real world setup, working in a production environment.

Did I get your attention? Read after the break, but take your time. it is a long read.

[Read More]

Running it through Tattr (part 2)

Some time ago I created a playbook to show the content of a rendered template. When you keep digging in the Ansible documentation, you suddenly stumble over the template lookup-plugin. And then it turns out that my playbook is a bit clumsy.

A nicer and shorter way to do it:

---
#
# This playbook renders a template and shows the results
# Run this playbook with:
#
#       ansible-playbook -e templ=<name of the template> template_test.yml
#
- hosts: localhost
  become: false
  connection: local

  tasks:
    - fail:
        msg: "Bailing out. The play requires a template name (templ=...)"
      when: templ is undefined

    - name: show templating results
      debug:
        msg: "{{ lookup('template', templ) }}"
[Read More]

Ansible, loop in loop in loop in loop in loop

A couple of days ago a client asked me if I could solve the following problem:

They have a large number of web servers, all running a plethora of PHP versions. These machines are locally managed with DirectAdmin, which manages the PHP configuration files as well. They are also running Ansible for all kind of configuration tasks. What they want is a simple playbook that ensures a certain line in all PHP ini files for all PHP versions on all webservers.

[Read More]

Did you run it through TAttr

During my last Ansible training the students needed to create some Ansible templates for them selfs. As I do not want to run a testing template against some, or all, machines under Ansible control I created a small Ansible playbook to test templates.

This is the playbook:

---
#
# This playbook renders a template and shows the results
# Run this playbook with:
#
#       ansible-playbook -e templ=<name of the template> template_test.yml
#
- hosts: localhost
  become: false
  connection: local

  tasks:
    - fail:
        msg: "Bailing out. The play requires a template name (templ=...)"
      when: templ is undefined

    - name: do template
      template:
        src: "{{ templ }}"
        dest: "/tmp/{{ templ }}"

    - name: get template
      command: cat "/tmp/{{ templ }}"
      register: tmplt

    - name: show template
      debug:
        msg: "{{ tmplt.stdout.split('\n') }}"

    - name: remove template
      file:
        path: "/tmp/{{ templ }}"
        state: absent
[Read More]

Stupid Fedora

Yesterday I removed a simple package from my Fedora 23 machine and after that I got the message

error: Failed to initialize NSS library

WTF??????

Searching the interwebs I found out I wasn’t the first, and probably not the last, to run into this problem.

It seems that, one way or another, the DNF package doesn’t know about the dependency it has on SQLite. So, when a package removal requests to remove SQLite, DNF removes it without questions. Ans thus break itself.

[Read More]

Docker panics

This morning I was messing around with Docker and I wanted to build me a nice, clean container with Ubuntu in it, to test Ansible thingies. I’ve done that before and everything worked as a charm. Until today.

I have this Dockerfile (I’ve stripped it to the bare bones that still fail):

FROM ubuntu:latest
MAINTAINER Ton_Kersten
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get -y update
RUN apt-get -y upgrade
RUN apt-get -y install git git-flow
RUN apt-add-repository -y ppa:mozillateam/firefox-next
RUN apt-get install -y firefox
[Read More]

Ansible @ Loadays

Last Saturday I attended Loadays in Antwerp, Belgium.

After listening to Jan Piet Mens’s talk about Ansible, I was up for it.

At 11:30 sharp, I started my own presentation for an almost packed room. It’s called Ansible, why and how I use it and you can find it on SpeackerDeck.

It was a lovely talk, with a very knowledgeable crowd.

Please, have a look at it and if you have any questions, let me know.

[Read More]

rsync on a not standard port

Today a colleague asked me to sync some files to a server that is not listening on SSH port 22.

I normally create a configuration entry in my ~/.ssh/config file, like

Host tosync
    Hostname syncer.example.com
    Port 1234
    User syncuser

and then command

rsync -va --progress --inplace . tosync:

But this time I didn’t want to create the entry in my SSH configuration, because I need this trick in a script. So I started to read the rsync manpage and after some experimenting I found

[Read More]

Resize a partition

I often have to increase the size of a virtual disk on a virtual machine. But I always seem to forget how to do it. I guess I have done it over a 100 times and I cannot remember exactly how I did it. So this blog entry is to help people on how to do this and as a reminder to myself.

This example is done on a virtual machine with CentOS 6, but it can be done on every Linux. And in the fdisk examples I have left out some of the not to interesting lines.

[Read More]

git status in the prompt

Working with git a lot I decided I needed some git status in my prompt.

I searched the web and some solutions where almost what I wanted and this one by Sebastian Celis came very close.

But it didn’t work with my version of zsh, because that didn’t seem to understand the =~ operator.

I also think Sebastian makes things over complicated and so I changed some things aroud.

This is what I came up with:

[Read More]