Akom's Tech Ruminations

Various tech outbursts - code and solutions to practical problems

Linux XFCE: Chrome Steals Focus on click despite mouse-focus mode

Posted by Admin • Thursday, February 29. 2024 • Category: Linux

I like to use mouse-focus mode in Linux (XFCE), which also means that I don't want windows to get raised on click.  This means, for example, that I can have a piece of a window visible but not raised and copy something to/from there:

The terminal is not raised on click

However, Google Chrome does not honor this window manager setting.  Any click in a chrome window causes it to be raised.

It turns out that, with XFCE's xfwm, there is an additional setting to turn off in gconf:

XFCE Settings
Turning off raise_with_any_button stops Chrome from stealing focus

Automating minikube configuration to log in to a Docker Private Registy.

Posted by Admin • Tuesday, March 14. 2023 • Category: DevOps

In CI, I am using minikube for local testing on my nodes.  In the name of repeatable builds, I completely rebuild minikube after each build (minikube delete, minikube start).   I am also using an internal Docker Private Registry (DPR or DTR).  Same methodology applies if you are using Google Container Registry or the Amazon equivalent.  In order to authenticate to DPR, I am using the registry-creds addon.  It is normally configured interactively:

$ minikube addons configure registry-creds

Do you want to enable Docker Registry? [y/n]: y

It then asks you some questions and expects user input.  

Automating

I want this automated, as it will be running several times an hour.  The addon config does not take any parameters, so I'm taking a different approach.  The configure step creates some credentials in k8s, and it is possible to transfer them from one cluster to another.  This is how I am doing it:

Continue reading "Automating minikube configuration to log in to a Docker Private Registy."

Linux Upgrading a non-LTS Ubuntu installation after EOL

Posted by Admin • Thursday, September 1. 2022 • Category: Linux

If you don't upgrade a non-LTS release (eg: 21.10) to a supported version before End-Of-Life, you will be dealing with a rather awkward user experience.  Here is what happens:

$ do-release-upgrade

Please install all available updates for your release before upgrading.

Yet if you atempt to install updates, that fails:

$ apt dist-upgrade -y

Err:5 http://archive.ubuntu.com/ubuntu impish Release
  404 Not Found [IP: 2001:67c:1562::18 80]

...

Essentially, apt cache knows about some pending updates, but the actual packages are not longer available.  You can't update them, so you can't upgrade your OS.

Continue reading "Upgrading a non-LTS Ubuntu installation after EOL"

Linux Upgrading a non-LTS Ubuntu installation after EOL

Posted by Admin • Thursday, September 1. 2022 • Category: Linux

If you don't upgrade a non-LTS release (eg: 21.10) to a supported version before End-Of-Life, you will be dealing with a rather awkward user experience.  Here is what happens:

$ do-release-upgrade

Please install all available updates for your release before upgrading.

Yet if you atempt to install updates, that fails:

$ apt dist-upgrade -y

Err:5 http://archive.ubuntu.com/ubuntu impish Release
  404 Not Found [IP: 2001:67c:1562::18 80]

...

Essentially, apt cache knows about some pending updates, but the actual packages are not longer available.  You can't update them, so you can't upgrade your OS.

Continue reading "Upgrading a non-LTS Ubuntu installation after EOL"

Linux Preserving a Static Copy of Atlassian Jira (and Confluence) as a Jekyll Site

Posted by Admin • Monday, October 25. 2021 • Category: Linux

Last month an old Jira installation I own was compromised via a recent vulnerability. This is bound to happen. Keeping a public product like that secure would require very frequent patching, which is a lot of maintenance. Fortunately, this installation is only a historical record of a popular open-source project (current development uses github issues). In other words, I can get away with a static, read-only copy.

Going Static

Of course, I can use

wget --mirror

to save the whole site exactly as-is. This is a simple option, but it will also need a lot of massaging (for example, to remove confusing links to login, javascript that may break, etc).

Instead, I'm going to convert the content to markdown so that I can then regenerate the site using Jekyll, changing the look and feel, headers and footers as needed. This will also preserve all existing URLs (including attachments).

Making this Happen

I wrote a project to help automate this process fully via the Jira API: https://github.com/akomakom/jira-to-jekyll/.

The basic goal is to do what I outlined above. There is a comprehensive README that explains the process.

Continue reading "Preserving a Static Copy of Atlassian Jira (and Confluence) as a Jekyll Site"

Linux Bootstrapping S3/CloudFront with LetsEncrypt

Posted by Admin • Thursday, August 5. 2021 • Category: DevOps, Linux

Let's assume that you want to do the following:

  1. Host the contents of your S3 bucket via YOUR.DOMAIN.COM
  2. Use CloudFront
  3. Use a LetsEncrypt cert

"What's the problem?", you may ask. There are plenty of tutorials for this stuff. Not exactly. A CloudFront Distribution will not let you add a CNAME until you have an SSL cert, but you can't use certbot to auto-provision an SSL cert until you are hosting from your domain.

Solution

The easiest solution is to initially generate your SSL cert manually. You can then use something like certbot-s3front to auto-renew.

Details

Continue reading "Bootstrapping S3/CloudFront with LetsEncrypt"

Hardware Hacks Adventures in Modifying a UPS for external DC power and LiFePO4 batteries

Posted by Admin • Saturday, June 26. 2021 • Category: Hardware Hacks

I have an ancient APC Smart-UPS 1400 RMNET. It's a very nice UPS, but I have frequent multi-hour power outages and battery life becomes a problem. I have these issues:

  1. Short battery runtime, especially as batteries age
  2. Lead-acid batteries require frequent replacement and quickly lose capacity (and there are 4 of them)
  3. UPS will not accept 110v from a cheap generator (mine is a 700w). This means that I can't do a live power transfer from mains to this generator, and I have to reboot everything to switch

So, I had a few ideas

  • What if I could feed externally-generated DC battery voltage directly to the batteries? For example, via a generator powering a AC-DC power supply
  • What if I could substitute Lithium batteries for Lead-Acid? LiFePO4 would be ideal in this application because weight doesn't matter but the long cycle life does. A 4S pack would have a similar voltage to a 12v lead-acid battery

Continue reading "Adventures in Modifying a UPS for external DC power and LiFePO4 batteries"

Linux PowerShell on Linux doesn't find modules when run through Puppet

Posted by Admin • Thursday, March 11. 2021 • Category: DevOps, Linux

I'm running PowerShell on Linux for the sake of using PowerCLI. An interesting thing happens: when pwsh is run interactively, in a terminal, the following works fine when PowerCLI is already installed:

pwsh -c 'Get-InstalledModule VMware.PowerCLI'

When puppet runs it - it doesn't find the module:

Get-Package: /opt/microsoft/powershell/7/Modules/PowerShellGet/PSModule.psm1:9445
Line |
9445 |          PackageManagement\Get-Package @PSBoundParameters | Microsoft. …
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | No match was found for the specified search criteria and
     | module names 'VMware.PowerCLI'.

Error: 'pwsh -c "if (-not(Get-InstalledModule VMware.PowerCLI)) { Exit 1 }"' returned 1 instead of one of [0]

After some experimentation, I narrowed it down to a single environment variable missing when puppet executes the command: HOME. Set HOME, and powershell will find modules. That gets us the following recipe:

  $my_user = 'some_user'

  exec { 'Install PowerCLI':
    path    => ['/bin', '/usr/bin'],
    command => 'pwsh -c \'Install-Module -Force:$true -Name VMware.PowerCLI\'',
    unless  => 'pwsh -c \'if (-not(Get-InstalledModule VMware.PowerCLI -ErrorAction silentlycontinue)) { Exit 1 }\'',
    user    => $my_user,
    environment => [ "HOME=/home/${my_user}"]
  }

Java Gradle Toolchains Support - different JVMs for compile and test

Posted by Admin • Thursday, February 4. 2021 • Category: DevOps, Java

I'm testing a product that needs to be compiled with JDK 8 but tested (sometimes) on JDK 11. This is now possible to do with maven surefire (although that took some effort). With gradle, I was doing it as follows, which is terrible, even if the path comes from configuration:


// The old way:
test {
    executable = '/some/hardcoded/path/to/java'
}
 

Now that Gradle 6.7+ has built-in toolchains support, it's trivial to configure the compile toolchain:


java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(11)
    }
}
 

But what about tests? What if I want to test with a different JVM? It's a little more verbose:


test {
    JavaToolchainService javaToolchainService = project.getExtensions().getByType(JavaToolchainService.class)
    def launcher = javaToolchainService.launcherFor{
        languageVersion = JavaLanguageVersion.of(11)
    }
    javaLauncher = launcher
    environment 'JAVA_HOME', launcher.get().metadata.installationPath //if your tests care about JAVA_HOME
}
 

Linux Puppet recipe for setting up autossh via systemd

Posted by Admin • Thursday, November 19. 2020 • Category: DevOps, Linux

I've always set up autossh in /etc/rc.local, but with CentOS 8 that doesn't work well (things start too early, etc). Luckily, there is a nicer way using systemd templates. Essentially, all you have to do is create one symlink and one config file per instance of autossh.

Example:

Make a config file


/etc/autossh/mything.conf:

OPTIONS=-N  -M 20000 -R8888:1.2.3.4:8888 5.6.7.8


Make a symlink

ln -s /usr/lib/systemd/system/[email protected] /etc/systemd/system/[email protected]


Test

systemctl start [email protected]
journalctl -xe


But it's better to automate:

Puppet Recipe



define autossh(
    $service=$name,
    $args,
  ) {

    file {"/etc/systemd/system/autossh@${service}.service":
      ensure => link,
      target => '/usr/lib/systemd/system/[email protected]'
    } ->
    file {"/etc/autossh/${service}.conf":
      content => "OPTIONS=${args}"
    } ->
    service {"autossh@${service}":
      ensure => running,
      enable => true,
    }

}

# and example usage - random port forwarding
autossh{'mything': args => '-N  -M 20000 -R8888:1.2.3.4:8888 host1'}
autossh{'mything2': args => '-N  -M 20000 -R8888:1.2.3.4:8888 host2'}
 

Using puppet to set Windows Computer Description

Posted by Admin • Monday, May 18. 2020 • Category: DevOps

My company's security department decided to assign Antivirus exclusion policies based on the value of the windows computer description. That means that I need to set computer descriptions ( net config server /srvcomment:"new description" ) to the same value on a whole bunch of windows machines. Doing that by hand is unappealing, and I already have puppet, so here is a simple solution:


MYCLASS/lib/facter/wincomputer_description.rb


# Gets computer decscription from 'net config server'
Facter.add("win_computer_description") do
  setcode do
    output = `net config server`
    output.split(/\n/).find{|it| it.start_with?('Server Comment') }.gsub(/Server Comment[\s]*/,'')
  end
end
 

MY_CLASS/manifests/init.pp


class MY_CLASS(
  $computer_description = 'Some-new-description',
) {
  if ($win_computer_description != $computer_description) {
    exec { 'Set computer description':
      path => ["C:\\windows\\system32"],
      command => "net config server /SRVCOMMENT:\"${computer_description}\"",
    }
  }
}
 

Low Tech Hacks Replacing Dishwasher Circulation Pump Bearings without buying a whole new unit

Posted by Admin • Friday, April 26. 2019 • Category: Low Tech Hacks

I have a DW80j3020us/AA Samsung dishwasher. It has been producing a loud noise for some time, and the noise kept getting worse. It was a matter of time before it either seized or melted the motor. The reason I know that the problem is with the circulation pump is that the noise is only audible while it's washing (circulating), not while draining or filling. Clearly the problem could be the motor (bearings) or some part of the impeller/grinder (less likely).

Samsung Dishwasher

My options were:

  1. New dishwasher
  2. New Circulation Pump motor DD31-00008A ($150)
  3. Try to change the bearings (I've found nothing online about anyone doing this)

 

You can find lots of videos online on how to properly replace the circulation pump motor/assembly. I followed the guides for removing the internal components down to the food chopper, since the chopper is on the motor shaft. This takes about 20 minutes. After that, it was easy - all I had to do was pull the bottom cover off and remove 4 screws to get the motor out. Then a magical thing happened.

Continue reading "Replacing Dishwasher Circulation Pump Bearings without buying a whole new unit"

Android doing Optimizing app 1 of 1 on every boot

Posted by Admin • Friday, May 4. 2018 • Category: Android

The message appears for a good 15 minutes every time my phone boots up. I followed the usual suggestions (wipe cache partition), and that didn't help



Figuring out what app is causing this issue is the hard part. I did it with logcat (I happened to have the Android Studio installed, so logcat is a tab, and it displays the log automatically as the plugged-in phone is booting). You don't need the whole thing, just the adb tools so you can run "adb logcat"



At the moment when the message appears, I saw this in the log:

05-04 14:48:10.388 1230-1230/? I/PackageManager.DexOptimizer: Running dexopt (dex2oat) on: /data/app/com.alltrails.alltrails-2/base.apk pkg=com.alltrails.alltrails isa=arm64 vmSafeMode=false debuggable=false oatDir = /data/app/com.alltrails.alltrails-2/oat

Well, now I know what to uninstall. I didn't need Alltrails anyway.

Disabling Windows Recycle Bin with Puppet on all versions of Windows

Posted by Admin • Thursday, March 22. 2018 • Category: DevOps

And when I say "All versions of Windows" I mean that I tested it on Server 2008, 2012 and 2016.



This was oddly hard to figure out, and most tutorials either apply to only one version of windows or to outdated tools. The best way to do this that I found was using Local Group Policy. Now, how to automate this? The puppet localgrouppolicy module didn't work at all when I tried it (and has not been updated since 2014). The proper way to do this is of course with a Domain-based Group Policy, but my machines are not members of a domain.



Fortunately, there is a new Microsoft tool called LGPO that allows for some degree of command-line control of the Local Group Policy. Download "LGPO.exe" here.

First, let's make a reusable policy text file that we can import on all machines:

  1. take a vanilla Windows machine that hasn't had any Group Policy customization, and use lgpo.exe to export the policy: "lgpo.exe /v /parse /u c:\windows\system32\GroupPolicy\User\Registry.pol" (at least that was appropriate in my case). You should get more or less empty output.
  2. Then use the Local Group Policy Editor to change "Do not move deleted files to the Recycle bin" (under User Configuration -> Administrative Tools -> All Settings) to "Enabled"
  3. Repeat step 1. You should see this one setting that you changed in the output. Redirect output to a file, this will be our text file
  4. You can test that importing this file will change the setting: "lgpo /r myfile.txt". (Change the setting back first, run this, then re-open the Local Group Policy Editor to see the change)

Now, we can set up puppet:

Continue reading "Disabling Windows Recycle Bin with Puppet on all versions of Windows"

Jenkins Pipeline: parallel and waitUntil, waiting until the other branch finishes

Posted by Admin • Monday, January 22. 2018 • Category: DevOps

Let's say that for the sake of speed, you are running two slow things in parallel, but you want one to wait for the other.


parallel one: {
    node {
        sh "sleep 15"
    }
}, two: {
    node {
        //slow part:
        sh "sleep 10"  

        // now do something that needs "one" to finish.  There is a good chance that this will run too soon...
        sh 'wget http://something' //for example
    }
}
 

The problem, obviously, is that you can't be sure that the wget will run after part one finishes. (Let's assume that part one creates the file).

Continue reading "Jenkins Pipeline: parallel and waitUntil, waiting until the other branch finishes"