Search This Blog

Tuesday, July 28, 2026

KeePassXC sync, Dropbox and RPi

Intro

I keep my passwords in the KeePassXC DB and use Dropbox to synchronising it between multiple computers (and phones). It has been working fine for years, until I decided to try set RPi as a desktop. Dropbox does not provide a client for Arm architecture. However, as quite often in the world of open source, there is an alternative. Rclone is a tool allowing you to manage files in over 70 cloud provider, including Dropbox.

Software is easy to install and configure. Just run rclone config and follow prompts, choose Dropbox, authenticate via browser, as documented in the Dropbox section of the project website.

Sync

For syncing one file, rarely changed, a simple script around rclone is good enough. It provides 2 functions: pull and push.

#!/bin/bash
REMOTE="dropbox:path/to"
REMOTE_PATH="${REMOTE}/YourDB.kdbx"
LOCAL_PATH="${HOME}/keepass"
LOCAL="${LOCAL_PATH}/YourDB.kdbx"

case "$1" in
  pull)
    rclone copy "${REMOTE}" "${LOCAL_PATH}"
    echo "Pulled from Dropbox"
    ;;
  push)
    rclone copy "${LOCAL}" "${REMOTE_PATH}"
    echo "Pushed to Dropbox"
    ;;
  *)
    echo "Usage: $0 pull|push"
    ;;
esac

The script assumes that the name of the remote was set to dropbox and the local copy is stored in the ~/keepass directory. Note, that for the copy source is the name of the file, but destation is the folder.

Cronjobs

To to mimize a chance of reading outdated passwords it's worth to automated the pull step. Just pull, because KeePassXC handles conflicts well at the application level (it can merge databases), but rclone itself is not conflict-aware. Automated push can overwrite changes from another machines, or copy a corrupted file.

# Automated sync every half-hour
*/30 * * * * rclone copy dropbox:path/to/YourDB.kdbx ~/keepass/ --log-file=~/.local/var/log/rclone-keepass.log --log-level ERROR
# Extra daily backup
3 3 * * * rclone copy dropbox:path/to/YourDB.kdbx ~/keepass/$(date +\%Y-\%m-\%d)/ --log-file=~/.local/var/log/rclone-keepass-backup.log --log-level ERROR

Links

Tuesday, June 30, 2026

Cruxpy as an example of the python package release process

As mentioned beforeCruxPy helped me to automate the process of keeping the repository of my Crux ports rolling. It also gave me a chance to prepare a pipeline for a Python package with GitHub Action (GHA) workflows.

On every commit the GHA runs 2 jobs. First, pytest. When the tests pass, it checks the version stored in the pyproject.toml file, and compares it to the latest tag. If the version from the file is higher than the current tag, the new one is pushed. These jobs are stored in the commit.yaml file.

When there is a new tag pushed to the code, another workflow, from the release.yaml file, kicks off. It has only one job - to create a GitHub release.

The completion of the "New Release" job triggers the third workflow saved in the deploy.yaml file. It is responsible for publishing the python package to the pypi repository.

If you are just starting your adventure with GHA, you might want to check triggers to understand them better.  This pipeline uses three distinct types:

  • commit is defined as push to every branch (excluding tags)
  • release uses a push of a tag, that matches 3-number semantic version
  • deployment relays on the internal GitHub workflow dependencies.

This structure allows me to push changes directly to the main branch safely. Nothing becomes visible outside of repository until the version is bumped!

Friday, May 01, 2026

Watching GitHub PRs

In one of my previous posts I explained how to check the status of your PRs from the command line. Recently, I added one more improvement to ensure that also PRs without any reviews yet are listed with the PENDING state. This is achieved by using the fallback operator // in the jq\(.reviews[-1].state // "PENDING") command.


gh pr list \
 --author @me \
 --json "number,title,reviews" \
| jq '.[] | "PR \(.number): \(.title) is \(.reviews[-1].state // "PENDING")"'

I also discovered (with some help from AI) how to watch the PR state live in full colour: combine the watch tool  --color option with one of 2 environment variables:


watch --color 'GH_FORCE_TTY=1 gh pr view'
watch --color 'CLICOLOR_FORCE=1 gh pr view'
  • GH_FORCE_TTY=1: is the gh specific option and forces the GitHub CLI client to behave as it is running in a terminal, even if it's not (e.g. piped or run inside watch).
  • CLICOLOR_FORCE=1: is part of the CLICOLOR standard and affects other tools as well. It forces the tool to output colours regardless whether it is running in a terminal or not. 

Links

Sunday, April 26, 2026

Raspberry Pi hardware-related problems and settings adjustment to address them

Using a Raspberry Pi 4 as a desktop computer, I faced a few hardware-related issues. I diagnosed and fixed them with the help of AI assistants, which suggested specific commands and configurations.

Low Monitor Resolution

The first was the low resolution of the monitor. I have BenQ PD2500Q with a native resolution of 2560x1440, but RPi recognised it only as Full HD (1920x1080).

After some research, I found a suggestion to check the output of edid file from the /sys subsystem:

sudo cat /sys/class/drm/card*/card*HDMI*/edid| edid-decode

The output revealed the issue: the monitor was advertising 2560×1440 as a DTD (Detailed Timing Descriptor) in Block 0, but the CTA-861 extension block (Block 1) only listed standard HD modes up to 1920×1080 as native. The Pi's Wayland compositor (the display server protocol used by Raspberry Pi OS) was prioritizing the CTA block and stopping at 1080p.

The DTD timing can be explicitly set in the /boot/firmware/config.txt (It might be necessary to put the timings settings into one line):


[HDMI:0]
hdmi_group=2
hdmi_mode=87
hdmi_force_hotplug=1
hdmi_timings=2560 1 47 32 81
             1440 1 3 5 33 0 0 0
             60 0 241500000 6

However, after a restart, the resolution reverted to 1080p. Further investigation revealed that the window manager (labwc) also needed the custom mode to be set. I added the following line to ~/.config/labwc/autostart:

wlr-randr --output HDMI-A-1 --custom-mode 2560x1440@59.95 &

Very Slow Mouse

My mouse was lagging significantly. I first tried adjusting the mouse speed in the desktop environment settings, but it didn’t help.

After some research, I found that the issue could be resolved by adjusting the usbhid.mousepoll parameter in /boot/firmware/cmdline.txt. This parameter controls how often the USB mouse is polled for input (in milliseconds). Lower values mean more frequent polling and smoother cursor movement, but setting it too low can cause system instability.

I ended up with the following setting:

usbhid.mousepoll=4

Network Card Dropping Connection

The third problem was much easier to diagnose. I left RPi running, but when I returned, the WiFi connection had dropped. The logs revealed repeated failures during the 4-way handshake authentication process, with NetworkManager unable to retrieve the stored WiFi password.

The root cause was that the connection details were saved into a user session keyring (e.g., GNOME Keyring) rather than the system keyring. A user keyring unlocks when you log in and stays unlocked while your session is active; then it locks again, and NetworkManager cannot retrieve the password.

The solution was to set the password storage to system-level keyring using the nmcli tool:

sudo nmcli connection modify "YOUR_network" wifi-sec.psk "your-password"
sudo nmcli connection modify "YOUR_network" connection.permissions ""

The first command sets the WiFi password for the specified network connection, while the second removes any permission restrictions, allowing all users to access the connection.

Note: For security, avoid hardcoding passwords in commands. Instead, use nmcli interactively or a secure password manager.

The WiFi stability was also affected by the the power saving. It is controled by the NetworkManager confugration. To turn it of ensure that the /etc/NetworkManager/conf.d/wifi-powersave-off.conf file contains:

[connection]
wifi.powersave = 2

Remember to restart NetworkManager service for the setting to be activated

Links

Saturday, April 18, 2026

Crux cnijfilter2 package (Canon cups drivers)

I don't longer have a Canon printer, so I remove the cnijfilter2 package from my repo. To help any potential Canon printer user the Pkgfile is below. There is also a patch required by the build process.

Pkgfile

# Description: Drivers for Canon printers
# URL: https://www.canon-europe.com/support/consumer_products/operating_system_information/#linux
# Maintainer: Wawrzek Niewodniczanski, main at wawrzek dot name
# Depends on: cups

name=cnijfilter2
version=6.80-1
release=1
source=(https://gdlp01.c-wss.com/gds/2/0100012302/02/$name-source-$version.tar.gz
	add-missing-import.patch
	)

dirs="cmdtocanonij2 cmdtocanonij3 cnijbe2 lgmon3 rastertocanonij tocanonij tocnpwg"
build() {
	patch -p0 -i add-missing-import.patch
	cd $name-source-$version
	sed -i '/po\/Makefile.in/d' lgmon3/configure.in
	sed -i /SUBDIRS/s/po// lgmon3/Makefile.am
	sed -i '/GET_PROTOCOL/s/^int /static int/' lgmon3/src/cnij{lgmon3,ifnet2}.c
	export LDFLAGS="-L../../com/libs_bin_x86_64"
	for dir in $dirs
	do
	        cd $dir
	        ./autogen.sh \
		                --prefix=/usr \
		                --enable-progpath=/usr/bin \
		                --datadir=/usr/share
	        make
	        make DESTDIR=$PKG install
	        cd ../
	done
	rm -rf $PKG/usr/share/locale
	cd com/libs_bin_x86_64/
	rm lib*.so
	install -c lib*.so* $PKG/usr/lib
	declare -a libs
	libs=$(ls -1 lib*.so.*)
	for baselib in $libs
	do
	        shortlib=$baselib
	        while extn=$(echo $shortlib | sed -n '/\.[0-9][0-9]*$/s/.*\(\.[0-9][0-9]*\)$/\1/p')
	        [ -n "$extn" ]
	        do
		                shortlib=$(basename $shortlib $extn)
		                ln -s $baselib $PKG/usr/lib/$shortlib
	        done
	done
	cd -
	mkdir -p $PKG/usr/lib/bjlib2
	install -c -m 644 com/ini/cnnet.ini $PKG/usr/lib/bjlib2
	mkdir -p $PKG/usr/share/ppd/$name
	install -c -m 644 ppd/*.ppd $PKG/usr/share/ppd/$name
}
Patch

--- cnijfilter2-source-6.80-1/lgmon3/src/keytext.c	2024-09-20 07:28:40.000000000 +0100
+++ cnijfilter2-source-6.80-1/lgmon3/src/keytext.c.fix	2025-06-11 23:21:28.361664234 +0100
@@ -37,6 +37,7 @@
 #include <unistd.h>
 #include <libxml/parser.h>  /* Ver.2.80 */
 #include <string.h>
+#include <stdlib.h>

 #include "keytext.h"

Monday, March 30, 2026

More jq from journalctl

I've found another use case for `jq` when parsing service logs stored with journald. This time, I want to extract all non-INFO level logs from the service called slinky. In the previous example, I used awk to print only the part of a line that is valid JSON. However, sed might be better suited for this task. The following rule removes (replaces with an empty string) the beginning of the line up to the colon followed by a space ": ", which separates the timestamp from the log entry (JSON):

's/^.\+\]:\ //'

Examples

There are two examples of the command pipelines below. 

The first one checks the logs from the last 2 hours:


journalctl --since "2 hours ago" -u slinky.service\
 | sed -e 's/^.\+\]:\ //'\
 | jq 'select(.level != "info") '

The second one continuously prints new entries:


journalctl -f -u slinky.service\
 | stdbuf -oL sed -e 's/^.\+\]:\ //'\
 | jq 'select(.level != "info") '

The journalctl command is nearly identical in both examples (--since vs. -f). The jq select statement and the sed string replacement are the same. The main difference is that the latter uses the stdbuf command. It allows running the following command with modified buffering. The -oL option means that the standard output of the sed command is flushed line by line, enabling each entry to be passed immediately to jq.

Monday, March 02, 2026

Download GitHub Actions logs

I've been using GitHub CLI more and more lately. Recently, I had to debug a failing of GitHub Action run. Browsing long logs in the WebUI is a bit clunky, so I started downloading the full logs via the CLI. 

It is straightforward `gh` command if you already know the run number --  and that information can be obtained from the `gh` command with different options. 

I end up with following two-part shell snippet: 

VIEW=$(\
 gh run list \
 | grep $(git branch --show-current) \
 | head -1\
 | awk '{print $(NF-2)}') \
&& \
gh run view ${VIEW} --log > ~/Downloads/${VIEW}.log
 

The first command assign the run number to the VIEW variable. It parses the output of the `gh run list` command by:

  • filtering run for the current git branch (`grep`)
  • taking the most recent one (`head`)
  • extracting the run number (third column from the end via `awk`).

The VIEW variable is then used to fetch the logs for the specific run and save them to the uniquely named file in the Downloads folder.

Assumptions:

  • the workflow run belongs to the current git branch
  • it's the latest run for the branch 
  • The Downloads folder doesn't already contain a file with the same number (it would be overwritten)

Saturday, February 21, 2026

IvyNet DevOps Projects

Before IvyNet shut down, we decided to open-source the code. There are a few DevOps bits, which might be useful for others.

I believe documentation is important, and the README is a good starting point to see what's there. Good documentation doesn't have to be long or very detailed, so you'll find links to the actual code (e.g. Ansible, GitHub Actions, pre-commit, OpenTofu/Terraform, or Packer) plus some extra explanations.

Other things I'd like to point out:

The repository with OpenTofu/Terraform modules includes pre-commit and GitHub Actions (GHA). Each module has tests, documentation, and proper versioning. Some of the test scenarios are quite complex because they require extra components to run. https://github.com/ivy-net/otofu-modules 

The OpenTofu infrastructure definition is separated from the modules. This separation makes it easy to upgrade environments independently. Each can be upgraded separately, so you can test things in staging or dev before touching production.  https://github.com/ivy-net/infra

  
The applications are written in Rust, and the GitHub Actions and pre-commit setup could be a good starting point for Rust project automation. 

Tuesday, January 06, 2026

Hash of the latest git commit

From time to time I have, not only know, but to paste the hash of the latest git commit somewhere else. I prepared a one-liner to get the hash in a format good to copy & paste:
git log --pretty=oneline |\
 awk '{print $1}'

Wednesday, November 26, 2025

Check status of your GitHub PR from CLI

This github CLI command (`gh`) will list each PR authored by you. The output contains the PR number, title and all reviews. They are printed as json, and piped to `jq`. From the output, jq filters out the id, title and state of each review and interpolate it into a string.

gh pr list \
 --author @me \
 --json "number,title,reviews"\
 | jq \
 '.[] | "PR \(.number): \(.title) is \(.reviews[].state)"'

Links

Monday, November 03, 2025

IP address oneliner

Command

The command to get a public IP from UNIX `ip addr` command:

ip -4 -o addr| \
 awk -F "( |/)" '$0 !~ " (10|127|172|192)\\." {print $7}'

The `ip` command options makes it to print only IPv4 addresses (`-4`) and output them in one line each (`-o`).

The `awk` app uses space and `/` as Field separators (`-F "( |/)`) and looks for lines without a substring containing one of 10, 127, 172, 192 numbers followed by a dot and preceded by space (`$0 !~ " (10|127|172|192)\\."`. It prints a seventh filed (`{print $7}`).

Example of ip command output

To better understand the pattern used in the `awk` below is an example of the output of the `ip` command.

1: lo    inet 127.0.0.1/8 scope host lo\       valid_lft forever preferred_lft forever
2: enp2s0f0np0    inet 56.112.121.59/32 metric 100 scope global dynamic enp2s0f0np0\       valid_lft 64241sec preferred_lft 64241sec
4: docker0    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0\       valid_lft forever preferred_lft forever

Wednesday, September 24, 2025

Json in logs and how AWK can help

Checking systemd service logs in a JSON format might be a bit annoying. The output is far from readable, but AWK comes to help. The key is to use the "{" character as a separator, and reusing it in the printf command.

In my case, I had to check the mev-boost outputting in JSON format and used the following command to make the output more readable. 

 journalctl -u mev-boost --since "2025-09-22 00:00:00" | \
  awk -F{ \
  '$0 !~ /io.ReadCloser/ { printf ( "%s%s\n" ,FS ,$2) }' | \
  jq .
 

The first line limits the output of journal logs to unit `mev_boost` from 22nd September 2025.  Second and third line direct AWK to split each line on the "{" character, and processes only lines which do not contain the string "io.ReadCloser". The lines with the string are not proper JSON. Next, the second field/substring is printed, but prefixed with the field separate ("FS"). Otherwise, the output will not be a valid JSON, because the opening "{" is used a separator. Such formatted line is then sent to jq. In the example, jq just prints the output in a human friendly way, but it can be used to query the output.

Wednesday, September 17, 2025

Crux Port Automation

Crux ports 

To simplify keeping my Crux port repository up to date, I set GitHub Actions. There are 2 at the moment. The first one is the simple check of basic rules (trailing white spaces, lack of big files etc.) implemented with pre-commit.

The second one provides the crucial automation. The script takes the repository code, downloads the cruxpy library (see below for details). Then it gets Crux httpup-repgen script from the private s3 bucket. (Stored there to avoid 3rd party dependencies). It uses a very simple python script (portspage.py) to create a page for ports and then port-sync.sh to create the REPO file and upload the whole repo to the server. The SSH keys required to log in to the remote machine are stored in GitHub secret.

CruxPy

Initially, my automation based on standard Crux scripts. I was copying the repository from my desktop, even if the source code was stored in GitHub. Then I introduced GitHub Actions. The automation kept working from the remote machine fine. But there was a small issue. The last update date of ports in web UI was populated with the timestamp of the last file update on the GHA runner. They all were the same, because the code was downloaded every time. To fix it, I decide to prepare the CruxPy, a simple Python module.

Initially, I thought of preparing an equivalent of portspage.sh script, but with ports update date using git file metadata. Drafting the solution, I decided that the object-oriented approach suites the problem well; a port is an object, the repository website is as well. And in the future, the port class can be also used to prepare a repo one, and write CLI tools.

Having basic classes, I thought that it would be a great opportunity to prepare my first Crux package and add some automation. Which deserve a separate article.

Links

Thursday, August 28, 2025

Check the time of the current block in a Cosmos blockchain

echo BLOCK: $(curl -s 127.0.0.1:26657/status |\
 jq -r '.result.sync_info.latest_block_time');\
echo "NOW:   $(LC_TIME=C date -u +%Y-%m-%dT%X.%NZ)" 

Blockchain perspective 

If you deal with a Cosmos based blockchain, this command (actually there are 2 commands) helps to visualise the difference between the time of the latest block and current time. That's helpful if a node needs to catch up (e.g. after restarting from a snapshot). 

UNIX perspective 

The command has a few interesting "UNIX features". First, the curl from the localhost is silent (-s option) to avoid showing download stats. Its output is redirected to jq, which presents the raw (-r option) the time of latest block (.result.sync_info.lastest_block_time field). 

The second command returns the current time. The LC_TIME=Csets the locale to a standard, non-localized format, ensuring the output is always in a 24-hour clock and not a 12-hour AM/PM format, which can vary by location.  The option -u forces the output in the UTC, rather than the local time. Finally, +%Y-%m-%dT%X.%NZ formats date identical like the cosmos endpoint. 

Tuesday, July 15, 2025

Take me to the git home (and checkout me back)

I'm moving quite a lot around git projects. For some time, I have been wondering if there is a way to have an equivalent of argumentless `cd`. But rather of taking you back $HOME, changing directory to the git top-level one. I decided to make a deeper dive into the problem and ended up with the following function in zsh:

  function cdt ()
   cd $(git rev-parse --show-toplevel)}

Originally, I had an alias, but it did not work as designed. It took a root of git repository when sources (usually, during shell start). For a refernce that is my original alias.

  alias cdt="cd $(git rev-parse --show-toplevel)"

Another "dimension" of git project you can move around are branches. Last year, I learnt that the `-` works in the `git checkout` the same as in the `cd` command. So if we switch between branches, try:

  git checkout -

Monday, October 21, 2024

GRPC in Google Cloud

 

Recently, I've worked on setting up a GRPC endpoint behind the load balancer in the GCP (Google Cloud). That was a new project and in the first iteration we decided to serve it from a VM. The same machine was also the endpoint for the standard HTTP API. I set two load balancers to redirect traffic to each port. Both were healthy, but the GRPC didn't work properly. 

To my great surprise, I learnt that GRPC traffic requires not only HTTP2 protocol, but also a TLS/SSL setup on the server end of the internal connection (LB-VM). It has to be done, despite the fact traffic to be encrypted (with so-called automatic network-level encryption) [3]. The LB documentation kind of indicates the situation [1].  But initial, I could not believe, that Google, who introduce GRCP, could set it in such a messy way, and assumed that I didn't understand documentation properly. The fact that, AI didn't give a clear answer and hallucinated a few scenarios wasn't helpful. Only after a friend of a friend, who had faced the same issue before, confirmed that GCP cannot properly handle GRPC in LB, I found more documentation [2]

What really shocking is that the SSL/TLS certificate don't need to be valid at all. It can be an old, self sign. Doesn't matter. Just need to be there! It certainly does not need to be the certificate used by the LB

We automate VMs setup with Ansible [4], so I prepared a small script to set the SSL certificate. It's generic enough to be useful for others with minor adjustment. The code can be found at the end of the article. The "path variables" should be changed. Changing the DNS subject might also be not a bad idea, but probably it's going to work anyway, because the certificate does not need to be a valid one.

Summary

So to have GRPC behind load balancer in GCP you have to:

  • Prepare an External Application Load Balancer
  • Set HTTPS frontend (e.g. with certificate provided by Google)
  • Configure backend to be HTTP2 (with GRPC and HTTP2 health check)
  • Prepare an SSL certificate and ensure it's present at the end point 

Links

  1. https://cloud.google.com/load-balancing/docs/https
  2. https://cloud.google.com/load-balancing/docs/ssl-certificates/encryption-to-the-backends
  3. https://cloud.google.com/load-balancing/docs/https/http-load-balancing-best-practices
  4. https://ansible.readthedocs.io/

Ansible code

- name: Set  directory
  ansible.builtin.file:
    path: "{{ ivynet_backend_path_secrets }}"
    state: directory
    owner: root
    group: root
    mode: "0700"
  tags:
    - ssl

- name: Check if pem file exists
  ansible.builtin.stat:
    path: "{{ ivynet_backend_path_secrets }}/self.pem"
  register: pem

- block:
  - name: Create private key (RSA, 4096 bits)
    community.crypto.openssl_privatekey:
      path: "{{ ivynet_backend_path_secrets }}/self.key"
    tags:
      - ssl

  - name: Create certificate signing request (CSR) for self-signed certificate
    community.crypto.openssl_csr_pipe:
      privatekey_path: "{{ ivynet_backend_path_secrets }}/self.key"
      common_name: self.ivynet.dev
      organization_name: IvyNet
      subject_alt_name:
        - "DNS:grpc.test.ivynet.dev"
        - "DNS:self.test.ivynet.dev"
        - "DNS:test.ivynet.dev"
    register: csr
    tags:
      - ssl

  - name: Create self-signed certificate from CSR
    community.crypto.x509_certificate:
      path: "{{ ivynet_backend_path_secrets }}/self.pem"
      csr_content: "{{ csr.csr }}"
      privatekey_path: "{{ ivynet_backend_path_secrets }}/self.key"
      provider: selfsigned
    tags:
      - ssl
  when:
    - not pem.stat.exists
 



Tuesday, August 20, 2024

Pain with Names (of computing resources)

 

The good naming convention of computing resources (API, functions, ...) is an important aspect of code usability. Ideally, the names are short, but descriptive, follow some kind of conventions and allows people, who read or use code/product, intuitive usage, and easy documentation search. The Terraform (or OpenTofu) GCP (Google Cloud Platform) Provider is an example on how a small 'paper cuts' might make the experience painful.

Resources in GCP, at least some of them, can be global or regional. Each 'type' has the own API call (e.g. there is 'healthChecks', and 'regionHealthChecks'). Terraform follows the same convention. That's the first design decision to discuss. I, as the end user, would prefer GCP, or at least Terraform as a higher level language, to put them together in one resource type (e.g. healthCheck) and have an option inside in the resource to switch between them. However, Terraform covers a lot of providers, so I can guess (haven't searched the answer) there is a policy to translate underling API in the most direct way.

The real pain, is that there are no way to easy, general way to distinguish between regional and global resources. As mentioned above, default health check is global and regional has the 'region' prefix, but for the addresses the endpoint 'address' is regional and the global one has the prefix (globalAddress). Terraform follows. I don't know why API introduces the chaos, but I would much appreciate, if Terraform introduced an order. For example, everything what is regional, has a prefix region. If authors afraid of introducing problems by cross naming API endpoints and Terraform resources (e.g. a global_address become address and address: address_region), the solution could be to introduce a prefix for both types. Then we would have global_address and region_address.

Another problem is usage of prefixes rather than postfixes. As a user, I first look to create a load balancer and then decides if I want to make it global or regional. API and Terraform resources should make it easier for me, by exposing the more important resource feature first, on the left, e.g. address_global and address_region. Maybe global_address sounds better, but this is not a poetry and users don't read the code aloud. Using prefix makes searching and reading documentation harder, too. Methods and objects are usually listed in the alphabetic order, and with postfixes similar resource are next to each other, healthCheck is next to helthCheckRegion etc. It case of GCP would also make API usage a bit easier. The GCP API follows the Camel function name convention, and we have 'address', but 'globalAddress' ('a' vs 'A' in 'address'). With the postfix, it would be 'address' and 'addressGlobal'. The 'a' in 'address' would be always lowercase.

So what did go wrong for me with all of that? Recently, I've been working on a scenario to deploy a load balancer pointing onto a test VM. That took me too much time. The GCP documentation is rich. Quite a lot of APIs have Terraform resources examples, but not all of them. So I was patching them, with extra steps translating Console steps into Terraform using the GCP provider documentation. Some example were for regional resources, others for global one. The provider does not link between them. It took me too much time to figured out the right resource names. It was like this: "The error reads that the regional resource cannot point onto the global one. But why? I don't have any global resources. Oh, in this case, you have to add the word regional." I fixed them one by one. The last error was the address. On the Terraform provided docs page, I put "compute_address" in the search bar. And I read the help page over and over, looking on how to enforce the resource to be global. Finally, not sure how, maybe looking on one of the examples, I noticed that the address endpoint by default is regional, and I needed to add the 'global' prefix. Of course, in the search bar, I could type only 'address'. Unfortunately, for many resources keywords a search returns so many results, that they are not helpful, especially when you start the adventure with a new product.



Monday, April 22, 2024

Open geth (and other) binaries on MacOS

Recently, I had a problem opening the geth binaries (one of the Ethereum execution clients) on macOS.


 

After a short internet search, I found it was caused by extended attributes check. The problem like that occurs when the unsigned software is downloaded from the internet, but only using a web browser. When the curl or wget commands are used, there are no extended attributes assigned to the file.

 To check if the file has extra attributes, you can run a simple `ls -l` command and look for the `@` character.

> ls -l
-rwxr-xr-x@ 1 wawrzek  staff  45986920 17 Apr 07:06 geth
The list of attributes can be obtained with the `xattr` command:
> xattr geth
com.apple.quarantine
The same command can be used to remove the attribute
> xattr -d com.apple.quarantine geth
what enables an application to run.

Tuesday, April 09, 2024

Logitech MX Keys S on macOS and Linux (Crux)

 Before I forget again.

- On macOS, the UK keyboard is recognised as the ISO (International) one. That maybe causes the problem with the location of the ['`','~'] key. It's mixed up with the ['§','±'] one. I wrote maybe, because today I manually set it up to the ANSI option. That fixed the problem. But then, for a test, switched back to ISO, and it still works fine. Maybe my problem is because I connected the keyboard to a USB switch, rather than directly.

- Officially, Logitech supports Logi Option + software on Windows and Mac, but on Linux we have Solaar. It works, and if you are a Crux user, I created a port for it.

Sunday, February 04, 2024

Open file from command line (in Linux and Macos)

One of the nice feature of MacOS is the open command. It allows opening files directly from the command line without knowing the application linked to the file type. For example:

 open interesting.pdf 

opens the interesting.pdf file using whatever program is assigned to open PDF files. (If you want more example about the open command, you can check this link.)

For some time I wonder about a Linux equivalent. Recently decided to look for it more actively and check if AI might help. It did, and pointed at the gio command from the Gnome Input/Output library. After adding a function or an alias following block of code to the .zshrc, I have a Linux equivalent.

  •  alias

open="gio open"

  • function:

open () {

    gio open $1

}   

And finally, xdg-open is an alternative for the "gio open".