Akom's Tech Ruminations

Various tech outbursts - code and solutions to practical problems

Code and Hacks Customizing Windows 7 keyboard and mouse to act like Linux

Posted by Admin • Thursday, April 13. 2017 • Category: Code and Hacks

After using only Linux for nearly 20 years, I'm being forced to use a Windows machine for work. To make matters worse, I'm really (really) used to Enlightenment shortcuts, yet I use XFCE (Xubuntu). So, I'd like to have a seamless experience if I can help it. This is a log of my experimentation.



Note that I am not talking about a skin - I don't care that much about the looks, and I don't need the Windows desktop to look like Mint or Unity. What I want is for Windows to respond with the same level of fluidity that I get from Linux

Continue reading "Customizing Windows 7 keyboard and mouse to act like Linux"

Linux OCR on a large PDF using tesseract and pdftk

Posted by Admin • Thursday, January 19. 2017 • Category: Linux

This turned out to be harder than I thought. I found a large (50MB) PDF with about 50 pages, and none of the tesseract GUI's seemed to be able to handle it without crashing. The solution is to convert the PDF to TIFF so that command-line tesseract could handle it directly, but now ImageMagick couldn't handle that conversion as it was running out of memory (even with the limit settings). So the only option was to reduce the load on all the moving parts by splitting the PDF into pages.



Even after splitting the PDF and running each page through the PDF->TIFF->Tesseract->PDF chain I was still having issues:

Error in pixReadFromTiffStream: spp not in set {1,3,4}

Huh? So it turns out that sometimes you may wind up with an alpha channel in your TIFF and tesseract can't handle this. There is a solution, fortunately. So finally, I put all of these steps together into a script:

Continue reading "OCR on a large PDF using tesseract and pdftk"

Java Linux Running Jenkins Swarm client as a service via Upstart

Posted by Admin • Wednesday, December 21. 2016 • Category: DevOps, Java, Linux

This turned out to be fairly simple, with only one gotcha: do not follow the how-to's out there that tell you to use expect fork. The process doesn't technically fork. When I had that setting enabled, upstart commands would hang under very specific but repeatable conditions (if the process was killed externally).



So, here is my upstart conf file:

Continue reading "Running Jenkins Swarm client as a service via Upstart"

Linux Docker: Automatically remove containers that have been running too long

Posted by Admin • Thursday, October 20. 2016 • Category: DevOps, Linux

Why Because my Jenkins setup sometimes starts containers and forgets about them. Either it thinks it failed to start one, or the container itself has trouble starting. Either way, I'm left with containers that are running, trying to connect to Jenkins in vain, forever. The proper way to fix this is probably to have the containers timeout at some point, but that mechanism is broken.



Anyway, the fix I have is a true hack: find containers that have been up more than 2 days and kill them. None of our jobs should run for more than about a day, so this is a safe limit. Here is a bash script to do this:

Continue reading "Docker: Automatically remove containers that have been running too long"

Automotive Hardware Hacks Odometer Reprogramming - Nissan Sentra

Posted by Admin • Saturday, September 24. 2016 • Category: Automotive, Hardware Hacks

Disclaimer: It is perfectly legal to program an odometer to represent the correct mileage for the car.

Problem:

The car is a 2006 Nissan Sentra 1.8S. The instrument cluster is faulty and flips overdrive on and off at random. I ruled out the rest (switch, TCM). Thus, the cheapest option is to swap in another cluster, but that means that my mileage will be wrong. The replacement cluster I picked up on Ebay has 24K miles. Mine has 181K. Slight difference there.

Solution Summary:

Use an EZP2013 IC programmer to read the memory from your old cluster and write that to the new one. Clearly this assumes that you are still in possession of your old cluster and that its EEPROM is intact.

Solution Detail:

Continue reading "Odometer Reprogramming - Nissan Sentra"

Linux Jenkins command line ssh: Host key verification failed despite ssh-agent

Posted by Admin • Thursday, August 4. 2016 • Category: DevOps, Linux

After hours of "Why does it work locally but not in Jenkins", this error boils down to StrictHostKeyChecking... In other words, since the job runs as a user on a random slave, and this user most likely doesn't have a known hosts file with an entry for the target system, this fails rather cryptically. You think that the user's keys don't work, but that's not the problem.



The whole setup boils down to :

  1. Install ssh-agent plugin
  2. Configure credentials with a valid ssh key for your target
  3. Enable ssh-agent with that credential entry in your job config
  4. Add StrictHostKeyChecking=no to whatever ssh command you are using. Some examples:
    • GIT:
      export GIT_SSH_COMMAND="ssh -oStrictHostKeyChecking=no"
    • SSH:
      ssh -oStrictHostKeyChecking=no ....

Low Tech Hacks Replacing batteries in a Philips Norelco T980 Turbo Vacuum Trimmer

Posted by Admin • Wednesday, July 27. 2016 • Category: Low Tech Hacks

I bought this trimmer in 2008 and the NiCd batteries finally died in 2016 - not bad. Still, no reason to trash a working trimmer and contribute to the landfill problem. As it turns out, it's fairly easy to disassemble, and even easier to reassemble. So here are the steps, which probably apply to many similar models.

Continue reading "Replacing batteries in a Philips Norelco T980 Turbo Vacuum Trimmer"

Low Tech Hacks Replacing batteries in a Sonicare Elite toothbrush

Posted by Admin • Wednesday, July 27. 2016 • Category: Low Tech Hacks

I've had this toothbrush for over a decade, and the batteries finally died. I suppose that's a long time for NiCd cells to last. For the last year or so the toothbrush would not complete the 2 minute cycle but would instead stop sometime earlier. The batteries are clearly still alive but simply don't have enough capacity.



The toothbrush is not designed to be opened (it is waterproof after all). That should not stop us. The safest way of opening the casing that I could think of was cutting it with a PVC rope saw. This makes a relatively quick cut and mostly does not affect anything besides soft plastic. The circuit board was spared. The location of the cuts is important. I had no idea where the batteries would be so I took a guess and cut it in half. Pulling the two parts apart caused fine wires to get ripped out of the charge coil, something that I could have avoided had I just cut around the batteries. The ideal cut would be just tracing around the batteries on the back side, creating a "battery door" shape. The batteries are soldered directly to the circuit board, so they need to be carefully cut away so that extension wires can be soldered on to allow for some wiggle room.

Opening the casing the wrong way

Continue reading "Replacing batteries in a Sonicare Elite toothbrush"

Linux Ubuntu 18.04: Handling Dell Latitude laptop dock events to reconfigure displays

Posted by Admin • Tuesday, April 12. 2016 • Category: Linux

Couldn't find any good solutions out there. I have a Dell Latitutde E6410 running Ubuntu 15.10 (Update: these instructions worked fine on a Precision 7510 running Ubuntu 18.04) with XFCE (no Gnome or KDE). I use a physical docking station that allows me to use two external monitors. Ubuntu doesn't seem to understand that if these external monitors vanish, it should switch to the monitor that remains (built-in LCD), and vice versa, so I have to automate it myself. (Ubuntu 18.04 does in fact notice monitor changes, but insists on arranging the monitors in the wrong order, so this solution is still necessary)



The trick to doing this reliably is finding a udev device you can monitor using udev rules and perform actions when it appears or disappears. This would be a device that is 100% absent when undocked and is 100% present when docked. There is no kernel built-in dock device on these laptops. In order to watch what devices are coming and going, I used the following command (as root):

udevadm -p -u
udevadm monitor # in Ubuntu 18.x

Run that in a terminal, undock/dock and see what it says. You may want to save the output to a file, it's a lot. In my case, there was nothing definitive. There is "drm" device which sounds promising, but there is no good way to tell a "remove" apart from an "add" event. Ultimately, I settled on the numlock event. Why? Because it is specific to my external USB keyboard (Microsoft 4000) that is always plugged into the docking station. The internal laptop keyboard is unlikely to generate that event, and the full-size keyboard always produces one. Here is the relevant remove event:

Continue reading "Ubuntu 18.04: Handling Dell Latitude laptop dock events to reconfigure displays"

Code and Hacks Marking Jenkins build UNSTABLE from environment inject groovy script

Posted by Admin • Wednesday, March 23. 2016 • Category: Code and Hacks, DevOps
The way we use the Jenkins "Prepare an environment for the run" feature of the Environment Inject Plugin is this: we use the "Evaluated Groovy Script" to retrieve some info from a successful run of some other job (svn revisions, environment vars, whatever) in order to make it available to the environment of the current build. But what if that other job hasn't run successfully (yet)? I'd like to distinguish this "soft failure" from a real problem, so I'd like the build status to be "UNSTABLE". Here is how to do that in env inject:
currentBuild.@result = hudson.model.Result.UNSTABLE
However, that will not terminate the build. If you want to stop execution at this point, you'll have to put conditional logic in the job steps (but you can set a variable in EnvInject, and, for example, check it using Conditional Step)

Alternatively, to mark the build aborted and terminate immediately instead:

Screenshot:

Continue reading "Marking Jenkins build UNSTABLE from environment inject groovy script"

Linux Migrating Maven Jenkins jobs to FreeStyleJobs due to JDK 1.6 incompatibility

Posted by Admin • Tuesday, March 15. 2016 • Category: DevOps, Linux
Soon after Jenkins 1.609.1 support for JDK 1.6 was dropped altogether. This means that you can run jobs with whatever JDK you want as long as you are not using the Maven job type. Maven jobs require JDK 1.7 or higher (actually they run on whatever version the master is using, ignoring the JDK setting in the job configuration). This is a big deal for a shop that does extensive cross-platform testing. There are two solutions:
  1. Convert hundreds (in our case) of Maven jobs to regular (freestyle) jobs. There appears to be no simple script to do this, so I wrote one here
  2. Use maven toolchains to compile and test with a different JDK. Although converting jobs is a viable option that requires no additional setup, using toolchains may be preferred in some cases. For one thing, Jenkins offers the "Perform Release" button on maven jobs, something that is difficult to emulate in freestyle jobs.
Regarding option 1:

Initially I tried doing this using JobDSL, but that is way too time-consuming and hard to maintain. The simplest approach is to take the job XML, make minimal changes and push it back. Except that it's not that simple - you can't change the job type. You need to create new jobs, which is why I wrote a script to do all of the above. It will move the pre/post builders to the main builder list, and create a new maven job step in between. The rest is left unchanged and most of the XML is naturally valid for this version of jenkins/plugins since it's pulled from the live Jenkins.

Reviews Amazon no longer lists the items you ordered in emails

Posted by Admin • Wednesday, December 30. 2015 • Category: Reviews
Which is really a pity. When I search my mailbox for something I ordered, I'd like to find it. I should not have to remember where I ordered it and go to every store website. I tried to bring this up with Amazon customer service with entertaining results:


You are now connected to Pooja from Amazon.com
Me: How can I enable itemized order information in order confirmation emails? I understand that I can view it on your site, I am specifically asking about emails.
Pooja: Hello, my name is Pooja. I'm here to help you today.
Pooja: To be able to pull up your account please provide me your name, e-mail address and the billing address.
Me: My question is not account-specific
Pooja: May I please place you on hold for 2 minutes while I look in to this for you?
Me: Yes please
Pooja: I'm sorry but you'll not be bale to view the order details unless it is directed from the website.
Me: So when I order 10 items from Amazon I cannot have an email listing them?
Pooja: You'll receive an email confirmation for the items once you've completed the order/
Me: This email only lists the first one or two, followed by "... and 8 more items".
Pooja: In the email if you'd click on the link you'd be directed to the site for full item details.
Me: Can I have an email listing all the items?
Pooja: Would you like me to send you one ?
Me: I'd like you to send me one every time I place an order
Pooja: I'm sorry but that is not possible.
Me: Pity

Java Linux Jenkins: Bulk editing jobs to remove a trigger

Posted by Admin • Thursday, December 17. 2015 • Category: DevOps, Java, Linux
I have about 200 jobs that have the HudsonStartupTrigger (this is a plugin) turned on. This makes all of them run every time the master is restarted, causing the build queue to go crazy. I don't know why people turned this on in so many jobs (probably blindly copying jobs) over the years, but I'd like it gone. I don't want to restart the master or uninstall the plugin.

Here is a script console snippet to do this (can be adapted to remove other triggers easily). This does not do folders, if you're using that plugin.


import hudson.triggers.*
 
for (item in Hudson.instance.items) {
    name = item.name
       
  if (item instanceof AbstractProject) {
    triggers = ((AbstractProject)item).getTriggers()
   
    triggers.each{descriptor, trigger ->
      if (descriptor instanceof org.jvnet.hudson.plugins.triggers.startup.HudsonStartupTrigger$HudsonStartupDescriptor) {
            out.println("Removing startup trigger from job " + name)
        ((AbstractProject)item).removeTrigger(descriptor)
      }
    }
  }
}
 

Linux Suse11 cannot mount NFS share

Posted by Admin • Wednesday, December 9. 2015 • Category: DevOps, Linux
This is a recent issue on Suse 11.3. I have hundreds of machines mounting the same share fine - Centos, RedHat, even AIX.
mount -v /mountpoint                                                                                                               
mount.nfs: timeout set for Wed Dec  9 11:09:27 2015
mount.nfs: trying text-based options 'rsize=8192,wsize=8192,intr,hard,addr=X.X.X.X'
mount.nfs: prog 100003, trying vers=3, prot=6
mount.nfs: portmap query retrying: RPC: Program not registered
mount.nfs: prog 100003, trying vers=3, prot=17
mount.nfs: portmap query failed: RPC: Program not registered
mount.nfs: prog 100003, trying vers=2, prot=6
mount.nfs: portmap query retrying: RPC: Program not registered
mount.nfs: prog 100003, trying vers=2, prot=17
mount.nfs: portmap query failed: RPC: Program not registered
mount.nfs: prog 100003, trying vers=2, prot=6
mount.nfs: portmap query retrying: RPC: Program not registered
mount.nfs: prog 100003, trying vers=2, prot=17
mount.nfs: portmap query failed: RPC: Program not registered
mount.nfs: requested NFS version or transport protocol is not supported


Suprisingly, the problem is exactly what it says it is. Adding ",vers=4" to the options takes care of the problem. Hope this saves you time.

Puppet: recursively delete a Windows Registry key

Posted by Admin • Wednesday, October 14. 2015 • Category: DevOps
Puppet forge has a registry provider that allows one to manage a key or value. What it cannot do is delete a whole tree starting at a particular key. So, hacks to the rescue:


  # deletes the whole tree if it exists
  define registry_wipe_tree($key = $title) {
    exec {"Purge registry $key":
      path => ['c:/windows/system32'],
      command => "reg DELETE \"${key}\" /f",
      onlyif => "reg QUERY \"${key}\"",
    }
  }
 


Now if you want to, say, disable Java auto-update:

registry_wipe_tree{'HKLM\SOFTWARE\JavaSoft\Java Update':}
registry_wipe_tree{'HKLM\SOFTWARE\Wow6432Node\JavaSoft\Java Update': }