About Me

My photo
I know the last digit of PI

Friday, November 26, 2021

Running Kubernetes cluster on Windows

The easiest way to run kubernetes cluster on Windows is via Docker desktop Once you've installed docker dekstop click on the "Settings" / "Kubernets" and select "Enable Kubernetes".
Now you can execute kubectl command and it should succeed.
# kubectl get pods
No resources found in default namespace.

However the cluster is accessible only from the same machine since the cluster is listening on 127.0.0.1:6443 . As a workaround to allow remote connections a port proxy can be added. Use elevated command prompt and execute following command:
# netsh interface portproxy add v4tov4 listenaddress=192.168.0.42 listenport=6443 connectaddress=127.0.0.1 connectport=6443 protocol=tcp
It is important to replace the 192.168.0.42 with the machine IP address. Using 0.0.0.0 prevents the cluster from starting, so the specific IP address should be used.

Next step is to add a firewall rule that allows all connections to port 6443. Open elevated PowerShell and execute:
New-NetFirewallRule -DisplayName 'Docker Desktop Kubernetes cluster on 6443' -Profile 'Private' -Direction Inbound -Action Allow -Protocol TCP -LocalPort 6443

Copy the content of the %HOMEPATH%\.kube\config file to the remote machine and modify the host from "kubernetes.docker.internal" to "vm.docker.internal" and any occurance of the text "docker-desktop" to "remote-docker-desktop".
The final version of the config file should look like:
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: xxxxxx
    server: https://vm.docker.internal:6443
  name: remote-docker-desktop
contexts:
- context:
    cluster: remote-docker-desktop
    user: remote-docker-desktop
  name: remote-docker-desktop
current-context: docker-desktop
kind: Config
preferences: {}
users:
- name: remote-docker-desktop
  user:
    client-certificate-data: yyyyy
    client-key-data: zzzz

On the remote machine add "vm.docker.internal" to the /etc/hosts file
192.168.0.42 vm.docker.internal
Now executing kubectl command on the remote machine should succeed.
# kubectl get pods
No resources found in default namespace.

Monday, September 14, 2020

Transfer/Export/Copy Notes from one Mac to a another

Suprisingly the Notes application that comes with MacOS lack of export/import functionality. One workaround of that limitation is using Automator. However it exports only the notes text without the attachments.

Exporting notes from Mac 1:

  1. Open Automator from the applications.
  2. Create a new Workflow
  3. Choose Run JavaScript
  4. Copy/paste following export script:
    function run(input, parameters) {
    
    	const hexEncode = function(s){
        	let result = "";
        	for (let i=0; i < s.length; i++) {
            	hex = s.charCodeAt(i).toString(16);
            	result += ("0"+hex).slice(-2);
        	}
    
        	return result;
    	};
    	
    	const pad = function(n, size) {
        	let s = n + "";
        	while (s.length < size) {
    			s = "0" + s;
    		}
        	return s;
    	};
    
    	
    	const app = Application.currentApplication();
    	app.includeStandardAdditions = true;
    	const notesApp = Application('Notes');
    	notesApp.includeStandardAdditions = true;
    
    	const notes = notesApp.notes;
    	
    	const selectedNotes = app.chooseFromList(notes.name(), { withPrompt: "Select notes to export ?", multipleSelectionsAllowed: true });
    
    
    	if (selectedNotes) {
    		var destFolder = app.chooseFolder().toString();
    		let exported = 0;
    		if (destFolder) {
    			for(let i = 0; i < notes.length; i++) {
    				if (selectedNotes.indexOf(notes[i].name()) > -1) {
    					const fileName = destFolder + "/" 
    						+ pad(i, 9) + 
    						+ "." + hexEncode(notes[i].name())
    						+ "." + notes[i].modificationDate().getTime()
    						+ "." + notes[i].modificationDate().getTime()
    						//+ "." + hexEncode(notes[i].id()) 
    						+ ".html";
    					var f = app.openForAccess(Path(fileName), { writePermission: true });
    					app.setEof(f, { to: 0 });
    					app.write(notes[i].body(), {to: f});
    					
    					app.closeAccess(f);
    					
    					//const attachments = notes[i].attachments();
    					//if (attachments.length > 0) {
    					//	attachments[0].show();
    					//	app.displayDialog(attachments[0].id().toString());						
    					//}
    					
    					exported++;
    				}
    			}
    			app.displayDialog("Done. Notes exported: " + exported);
    		}
    	}
    
    	return input;
    }
        
  5. Click Run and select notes to be exported and destination directory (preferable empty one)
  6. Copy all notes files to destination Mac 2 (keep the original file names).

Importing notes to Mac 2:

  1. Open Automator from the applications.
  2. Create a new Workflow
  3. Choose Run JavaScript
  4. Copy/paste following export script:
    function run(input, parameters) {
    	'use strict';
    	
    	
    	const hexDecode = function(s) {
    		const hexes = s.match(/.{1,2}/g) || [];
    		let res = hexes.map(h => String.fromCharCode(parseInt(h, 16))).join("");
    		return res;
    	}
    		
    	const epochToStr = function(s) {
    		const lz = function (n) { return (n <=9 ? "0" : "") + n };
     	
    		const d = new Date(parseInt(s))
    		return d.getFullYear() + "-" + lz(d.getMonth() + 1) + "-" + lz(d.getDate()) + " " + lz(d.getHours()) + ":" + lz(d.getMinutes());
    	}
    
    	const app = Application.currentApplication();
    	app.includeStandardAdditions = true;
    	
    	const response = app.displayDialog("Prefix note titles with", {
        	withIcon: "note",
        	buttons: ["Modification date", "Note index", "Don't prefix"],
        	defaultButton: "Modification date"
    	});
    	
    	//0index.1title.2create.3modify.
    	let prefixColumn = -1;
    	switch (response.buttonReturned) {
    		case "Modification date": prefixColumn = 3; break;
    		case "Creation date": prefixColumn = 2; break;
    		case "Note index": prefixColumn = 0; break;
    	}
    	
        const finder = Application('System Events');
    	const folderName = app.chooseFolder().toString();
    	const fileNames = finder.folders.byName(folderName).diskItems.name();
    	
    	const notesApp = Application('Notes');
    	notesApp.includeStandardAdditions = true;
    		
    
    	const prefix = function (fileName) {
    		const titleItems = fileName.split('.');		
    		if (prefixColumn >= 0) {
    			titleItems[2] = epochToStr(titleItems[2]);
    			titleItems[3] = epochToStr(titleItems[3]);
    			return titleItems[prefixColumn];
    		} else {
    			return titleItems[0];
    		}
    	}
    	const prefixCoeff = prefixColumn == 2 || prefixColumn == 3 ? 1 : -1;
    	fileNames.sort(function(a,b) { return prefixCoeff * prefix(a).localeCompare(prefix(b)); });
    	
    	
    
    	for (let i = 0; i < fileNames.length; i++) {
    		const path = new Path(folderName + "/" + fileNames[i]);
    
    		const titleItems = fileNames[i].split('.');
    		titleItems[2] = epochToStr(titleItems[2]);
    		titleItems[3] = epochToStr(titleItems[3]);
    		const titlePrefix = (prefixColumn >= 0 ? "[" + titleItems[prefixColumn] + "] " : "");
    		const title = titlePrefix + hexDecode(titleItems[1]);
    		     	
    		const f = app.openForAccess(path);
    		const size = parseInt(app.doShellScript("stat -f%z " + path.toString().replace(" ", "\\ ")));
    		
    		try {
    			let content = "";
    		    if (size > 0) {
    				content = app.read(f);
    			}
    		
    			notesApp.make({ new:"note", withProperties: {name: title, body:content}});			
    		} catch (e) {
    			const msg = "Error processing file: " + fileNames[i] + " (title: " + title + "). Error message:" + e.toString();
    			app.displayDialog(msg + ". Do you want to continue?");
    			notesApp.make({ new:"note", withProperties: {name: title, body:msg}});
    		} finally {
    			app.closeAccess(f);
    		}
    	}
    	
    	app.displayDialog("Done. Notes processed: " + fileNames.length);
    
    	return input;
    }
    
  5. Click Run and select the folder containing notes exported from Mac 1

Sunday, July 21, 2019

Installing remote desktop server on Fedora 30

Installing remote desktop server accessible from Windows machines requires just a few steps:
  1. Install and enable the xrdp service
    sudo dnf -y install xrdp
    
    sudo systemctl start xrdp
    
    sudo systemctl enable xrdp
    
  2. Enable firewall rules
    
    sudo firewall-cmd --add-port=3389/tcp --permanent
    
    sudo firewall-cmd --reload
    

Saturday, February 23, 2019

Cloning bigger HDD with LVM into smaller SSD

HDDtoSSD

Recently I made an upgraded to one of my servers so I swapped a regular HDD with SSD. Unfortunately the HDD is 500GB but the SSD is 480GB, so the out-of-the-box cloning software won’t work. I tried using gparted and other free software with nice GUI but ended doing the job using the command line. I used ubuntu live cd
My original HDD is /dev/sde and the new empty SSD is /dev/sdb


Overview of the steps:

  1. Analyze the existing partition table
  2. Backup MBR and partition table
  3. Shrink the LVM
  4. Resizing the partition
  5. Copying the MBR and partition table
  6. Copying the partitions

Analyze the existing partition table

root@ubunto:/# parted /dev/sde unit s print
Model: HGST HTS 725050A7E630 (scsi)
Disk /dev/sde: 976773168s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
 
Number Start End Size Type File system Flags
1 2048s 7999487s  7997440s  primary ext2 boot
2 8001534s 976771071s 968769538s extended
5 8001536s 976771071s 968769536s logical lvm

So there is one primary partition for booting and one extended partition containing the LVM. Obviously it is not possible to move the extended partition directly without resizing it.

root@ubunto:/# lvm pvdisplay --map
--- Physical volume ---
PV Name /dev/sde5
VG Name vg0-11a111
PV Size  460.00 GiB / not usable 3.00 MiB
Allocatable yes
PE Size 4.00 MiB
Total PE 107519
Free PE 1280
Allocated PE 106239
PV UUID AAAAAA-bbbb-cccc-dddd-eeee-ffff-ggggg
--- Physical Segments ---
Physical extent 0 to 105564:
  Logical volume /dev/vg0-11a111/root
  Logical extents 0 to 105564
Physical extent 105565 to 107518:
  Logical volume /dev/vg0-11a111/swap
  Logical extents 0 to 1953

So the are two two logical volumes (/root and /swap). The only way to make space here is to shrink /root. It will also create a free space between /root and /swap, so /swap needs to be moved.

Backup MBR and partition table

Backup the partition table with following command:

sfdisk -d /dev/sde > part_table

It can always be restored later with:

sfdisk /dev/sde < part_table

The content of the part_table is

label: dos
label-id: 0xaaaaaaa
device: /dev/sde
unit: sectors

/dev/sde1 : start=        2048, size=     7997440, type=83, bootable
/dev/sde2 : start=     8001534, size=   968769538, type=5
/dev/sde5 : start=     8001536, size=   968769536, type=8e

The MBR (Master Boot Record) contains:

  1. Bootstrap - 446 bytes.
  2. Partition table - 64 bytes
  3. Signature - 2 bytes

So basically only the first 446 bytes needs to be backuped (the partition table is already contained in the part_table file). However it is always good to have the entire MBR. Creating a sde_mbr.bak file:

dd if=/dev/sde of=/tmp/sde_mbr.bak bs=512 count=1

It can later be restored by:

dd if=/tmp/sde_mbr.bak of=/dev/sde bs=446 count=1

or with partition table and signature

dd if=/tmp/sde_mbr.bak of=/dev/sde bs=512 count=1

Shrink the LVM

Before shrinking the volume should have enough free space.
Resizing the LVM volume with:

lvresize --resizefs --size 420G /dev/vg0-11a111/root

Now the information from pvdisplay looks like:

root@ubunto:/# lvm pvdisplay --map
--- Physical volume ---
PV Name /dev/sde5
VG Name vg0-11a111
PV Size  460.00 GiB / not usable 3.00 MiB
Allocatable yes
PE Size 4.00 MiB
Total PE 107519
Free PE 1280
Allocated PE 106239
PV UUID AAAAAA-bbbb-cccc-dddd-eeee-ffff-ggggg
--- Physical Segments ---
Physical extent 0 to 104284:
  Logical volume /dev/vg0-11a111/root
  Logical extents 0 to 104284
Physical extent 104285 to 105564:
  FREE
Physical extent 105565 to 107518:
  Logical volume /dev/vg0-11a111/swap
  Logical extents 0 to 1953

There is free space between LV /root and LV /swap , so the /swap should be moved wiht commnad line pvmove --alloc anywhere /dev/sde5:aaa-bbb /dev/sde5:ccc-ddd, where the aaa-bbb are the source physical extend and ccc-ddd are destination physical extend. It is better that ccc is equal to the end of the previous LV plus some space for safety.

pvmove --alloc anywhere /dev/sde5:105565-107518 /dev/sde5:104400-106353

After the move the pvdisplay looks like:

root@ubunto:/# lvm pvdisplay --map
--- Physical volume ---
PV Name /dev/sde5
VG Name vg0-11a111
PV Size  460.00 GiB / not usable 3.00 MiB
Allocatable yes
PE Size 4.00 MiB
Total PE 107519
Free PE 1280
Allocated PE 106239
PV UUID AAAAAA-bbbb-cccc-dddd-eeee-ffff-ggggg
--- Physical Segments ---
Physical extent 0 to 104284:
  Logical volume /dev/vg0-11a111/root
  Logical extents 0 to 104284
Physical extent 104285 to 104399:
  FREE
Physical extent 104400 to 106353:
  Logical volume /dev/vg0-11a111/swap
  Logical extents 0 to 1953
Physical extent 106354 to 107518:
  FREE

Now the last step is to resize the physical volume (note is 430G = 420GB for /root and 8G for /swap)

pvresize --setphysicalvolumesize 430G /dev/sde5

However the sde2 partition table is still having the original size, so it also needs to be resized.

root@ubunto:/# parted /dev/sde unit s print
Model: HGST HTS 725050A7E630 (scsi)
Disk /dev/sde: 976773168s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
  
Number Start End Size Type File system Flags
1 2048s 7999487s  7997440s  primary ext2 boot
2 8001534s 976771071s 968769538s extended
5 8001536s 976771071s 968769536s logical lvm

This can be achieved with cfdisk application with console UI - by setting the size of the sde5 to 431GB and sde2 to 432GB.
Alternatively it can be done by altering part_table file. Each sector is 512 bytes, so 431 GB = 903872512 sectors. The end file should look like:

label: dos
label-id: 0xaaaaaaa
device: /dev/sde
unit: sectors

/dev/sde1 : start=        2048, size=     7997440, type=83, bootable
/dev/sde2 : start=     8001534, size=   903872512, type=5
/dev/sde5 : start=     8001536, size=   903872510, type=8e

The partition table could be overriten with:

sfdisk /dev/sde < part_table

Confirming the change by

parted /dev/sde unit s print
Model: HGST HTS 725050A7E630 (scsi)
Disk /dev/sde: 976773168s
Sector size (logical/physical): 512B/512B
Partition Table: msdos
Disk Flags:
  
Number Start End Size Type File system Flags
1 2048s 7999487s  7997440s  primary ext2 boot
2 8001534s 903872512s 903872512s extended
5 8001536s 903872512s 903872510s logical lvm

Copying the MBR

Next step is to copy the MBR (bootstrap + partition table)

dd if=/dev/sde of=/dev/sdb bs=512 count=1

Alternatively partition_file could be used:

sfdisk /dev/sda < part_table

or directly without using a file

sfdisk -d /dev/sde | sfdisk /dev/sda

Copying the partitions

Final step is to copy the actual data from the partitions. Since dd doesn’t have any progress indicator, the pv utility comes in handy. It is not part of the ubuntu live cd, so it must be installed

apt install pv

Finally the following commands will copy the partitions data:

dd if=/dev/sde1 | pv | dd of=/dev/sdb1
dd if=/dev/sde5 | pv | dd of=/dev/sdb5

Alternative to steps 5 and 6 are to copy the entire disk.
First find out the number of sectors of the SSD

root@ubunto:/# parted /dev/sde unit s print
Model: ATA SanDisk SDSSDA48 (scsi)
Disk /dev/sdb: 937703088s
Sector size (logical/physical): 512B/512B
...

Then copy the entire disk

dd if=/dev/sde bs=512 count=937703088 | pv | dd=of/dev/sdb

Written with StackEdit.

Thursday, June 07, 2018

Generate random password with bash script

This is a utility script that generate random password
#!/bin/bash

size=10

if [[ "$1" == "-h" || "$1" == "--help" ]]; then
  echo "randpw [size]"
  exit 0
elif [[ "$1" != "" ]]; then
  size="$1"
fi

cat /dev/urandom | env LC_CTYPE=C tr -dc '!@#.1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM' | head -c$size
echo ""

Monday, May 07, 2018

Unmount all cifs shares before sleep/hibernate/suspend

I noticed when I close the lid of my laptop and there are mounted cifs shares, it takes 2 minutes before I am able to login after resume. I track down the problem to samba trying to reconnect mounted shares. The easiest way to fix that is to unmount everything before Fedora is going to sleep. Just create a script in /usr/lib/systemd/system-sleep/mounts with following content:
#!/bin/bash

case "${1}" in
  pre)
  # your command to umount here
    for m in `mount | grep /mnt | grep // | grep cifs | awk '{print $3}'`; do 
      echo "Unmounting $m"
      umount -f $m
    done 
  ;;
  post)
  # (possibly) your command to mount here
  ;;
esac

Monday, December 25, 2017

Backup samba shares from raspbery pi box

Here is a simple script that backups samba shares from linux box.
  1. Create backup script

    Create backup script and save it as /root/backup.sh
    #!/bin/bash
    
    # Gets the latest date and time
    DATE=`date '+%Y%m%dT%H%M%S'`
    
    # The root directory that contains the backups
    BACKUP_ROOT=/home/thexman/backup
    
    # Current backup directory
    BACKUP_DIR=$BACKUP_ROOT/$DATE
    
    # Current zip file
    BACKUP_ZIP=$BACKUP_ROOT/$DATE.zip
    
    echo "Creating backup directory $BACKUP_DIR"
    
    #create backup directory if it doesn't exists
    mkdir -p "$BACKUP_DIR"
    
    echo "Mounting samba share..."
    
    # Mount windows shares to /mnt
    mount -t cifs //192.168.99.93/c$ -o "username=administrator,password=1234" /mnt
    
    echo "Creating backup copies..."
    
    # Copy files from windows machine to backup directory
    rsync -rzvh "/mnt/temp" "$BACKUP_DIR"
    #rsync "/mnt/source_directory1" $BACKUP_DIR
    #rsync "/mnt/source_directory2" $BACKUP_DIR
    #rsync "/mnt/source_directory2" $BACKUP_DIR
    
    echo "Creating zip archive $BACKUP_ZIP"
    
    # Archive the backup directory to zip file
    cd "$BACKUP_ROOT" && zip -r "$BACKUP_ZIP" "$DATE"
    
    echo "Removing backup directory $BACKUP_DIR"
    
    # Remove the backup directory
    rm -rf "$BACKUP_DIR"
    
    echo "Umounting samba shares..."
    
    # Release windows shares
    umount /mnt
    
  2. Schedule backup script

    Execute following command "sudo crontab -e" and append following at the end of the file (it will execute the script at 21:15 every day)
    # m h  dom mon dow   command
    #15 21 * * * /root/backup.sh
    

Sunday, November 20, 2016

Convert MBR to GPT and BIOS bootable to UEFI bootable without data loss

Convert MBR to GPT

Instructons for Windows users

  1. Clone the disk in order to have backup data. You can skip this step but if somethings goes wrong the data on the disk may be lost
  2. Identify the disk which will be converted. Open Windows Disk Management and look the number (e.g. Disk 0).
  3. Download gptgen from sourceforge http://sourceforge.net/projects/gptgen This tool will allow you to convert the paritition table without loosing any data
  4. Unzip and start gptgen under elevated CMD (via Run as Administrator)
    gptgen.exe -w \\.\physicaldriveX
    Replace physicaldriveX with the disk number (e.g. physicaldrive0)
Now the disk should be converted to GPT. If you face a problem that the disk doesn't have enough space at the end of the disk, then you can shrink the volume (assuming that you have free space on the volume). This can be done with 3d party tools or with diskpart
  1. Open elevated CMD and run
    diskpart
  2. list volume
  3. select volume
    and choose the number of the corresponding volume (e.g. 0)
  4. shrink
  5. exit
  6. Rerun gptgen

Instructions for Linux

  1. Boot and open terminal. You need parted installed
  2. Make backup of the existing MBR partition table:
    parted /dev/sda unit s print > partition_table.txt
    If you are converting the disk with the operating system you are currently running copy the partition_table.txt file to USB drive or upload it to internet, so you can access it later if something goes wrong.
  3. Create new GPT partition table overriding the existing MBR table
    mktable gpt
    When asked choose to ignore the warnings and to continue (with overwriting). We will recreate the existing partitions on exact sectors they have been before, but with new partition table format.
  4. Recrete partitions by using the information from partition_table.txt file and commands
    unit s
    mkpart
    When asked fill the partition type (e.g. ext4) and partition starting/ending sector (see partition_table.txt)
  5. Optionally set the legacy boot flag to the corresponding partition number.
    set 1 legacy_boot on
  6. Print the partition table and compare it with the partition_table.txt file
    print

Convert BIOS bootable to UEFI bootable for GPT partitioned disk

Since it is difficult to do the conversion while running the operating system I suggest you download a Fedora live CD and create bootable USB drive, so you can boot from it. Make sure that the USB is UEFI bootable - this means when you write it with rufus, choose GPT partition table and FAT32 system. If you plan to convert Windows to UEFI, then you need also a Windows installation DVD or USB. Then change the boot type in BIOS from Legacy BIOS to UEFI - see docs from your commputer manifacturer how to do it.

In order for UEFI to work you need a new partition with type C12A7328-F81F-11D2-BA4B-00A0C93EC93B - EFI System Partition (ESP). The new partition should be formatted with FAT32 system. The partition should be the first one. It will contain the files required to boot the operating system(s).

Windows

In GPT Windows needs additional partition called Microsoft Reserved Partition (MSR). In standard MBR partition scheme Windows used hidden sectors to store system data, but GPT doesn't allow hidden sectors, so MSR partition is used instead. It should not be formatted with any file system, because its sectors will be used directly by the operating system. The partition type should be E3C9E316-0B5C-4DB8-817D-F92DF00215AE.

How to create the ESP and MSR under Windows

This guide is adapted from Technet article
  1. Boot from Windows installation DVD or USB
  2. Choose repair and open command prompt
  3. Start diskpart
  4. Select the disk where the ESR and MSR partitions will be created
    list disk
    select disk X
    Replace X with the disk number (e.g. 0)
  5. Usually you have one small bootable partition used to boot Windows. We are going to delete it and use the space to create a new ESR and MSR
    list partition
    select partition 1
    delete partition
  6. Now create ESR
    create partition EFI size=100 offset=1
    format quick fs=fat32 label="System"
    assign letter=S
  7. Now create MSR
    create partition msr size=128 offset=103424
  8. Find out the windows installation drive letter.
    list volume
    You can also reassign it if needed (Usually it should be C:)
    select volume 3
    assign letter=C
  9. Exit disk part
    exit
  10. Generate boot partiton data
    bcdboot c:\windows /s s: /f UEFI
    Replace C: with your Windows installation letter

Linux

TODO : (draft version) 1. Delete /dev/sda1 2. Shring /boot and move it at the end, so the begining of the disk is free space 3. Create ESR at begining 4./etc/fstab -> mount UUID=xxxxx to /boot/efi 5.copy livecd /boot/efi to /dev/sda1 (UUID=xxxx)

Sunday, October 30, 2016

Keyboard back light under linux.

For some reason my fedora is turning the keyboard back light off. Even if I press the keyboard shorcut to turn the light on, it doesn't work. For a long time I thought that the reason is hardware problem, until I found this post and it turns out to be software issue. Here is the script that I used on my machine to restore the keyboard light. Execute following command line several times until it outputs "100" (percents)
kb-light.py +
or
kb-light.py --up
The python script:
#!/usr/bin/env python3
# coding: utf-8

from sys import argv
import dbus


def kb_light_set(delta):
    bus = dbus.SystemBus()
    kbd_backlight_proxy = bus.get_object('org.freedesktop.UPower', '/org/freedesktop/UPower/KbdBacklight')
    kbd_backlight = dbus.Interface(kbd_backlight_proxy, 'org.freedesktop.UPower.KbdBacklight')

    current = kbd_backlight.GetBrightness()
    maximum = kbd_backlight.GetMaxBrightness()
    new = max(0, current + delta)

    if new >= 0 and new <= maximum:
        current = new
        kbd_backlight.SetBrightness(current)

    # Return current backlight level percentage
    return 100 * current / maximum

if __name__ == '__main__':
    if len(argv[1:]) == 1:
        if argv[1] == "--up" or argv[1] == "+":
            # ./kb-light.py (+|--up) to increment
            print(kb_light_set(1))
        elif argv[1] == "--down" or argv[1] == "-":
            # ./kb-light.py (-|--down) to decrement
            print(kb_light_set(-1))
        else:
            print("Unknown argument:", argv[1])
    else:
        print("Script takes exactly one argument.", len(argv[1:]), "arguments provided.")

Sunday, October 02, 2016

How to monitor progress of linux command dd.

If you start a dd command from the command prompt, there is no progress output. The easiest way to get the current dd progress is by executing following commmand from different terminal
sudo kill -USR1 $(pgrep ^dd)
The progress will be printed in the dd terminal. To print the progress every 5 seconds use
watch -n5 'sudo kill -USR1 $(pgrep ^dd)'
For dd version 8.24 and above the following command line will print the progress
dd status=progress  if=xxx of=yyy

Thursday, June 30, 2016

NGINX Reverse proxy and load balancer for Java servers

This is a simple script for the load balancing and reverse proxy configuration for an application called "myAppName" which runs on two servers "https://xxxxx:8080/myAppName" and "https://yyyyy:8080/myAppName". The script is designed for Java servers (tomcat, glassfish, jboss, etc.)

However please note that since NGINX open source doesn't support sticky it is not suitable for productive environments load balancing, because it uses ip_hash directive, which tells nginx that all request from particular IP to be served by one and the same server. If that IP is the external IP of large internal LAN (via NAT), then it means only one server will be loaded, which may crash that server. If you are not willing to pay $1900/yr then stick to apache httpd.

There are two options - the reverse proxy machine is serving all requests on the root "/" or "/myAppName".

worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;
    
    # Load balancing    
    upstream myAppName {        
        ip_hash;
        server xxxxx:8080;
        server yyyyy:8081;
    }
    
    server {
        listen       1080;
        server_name  localhost;

        location / {
            rewrite ^/myAppName/(.*)$  /myAppName/$1 break;
            rewrite ^(.*)$  /myAppName/$1 break;
            proxy_pass http://myAppName;
            proxy_cookie_path / /myAppName;    
        }
        
        #location /myAppName {            
        #    proxy_pass http://myAppName;
        #    proxy_cookie_path /myAppName/ /myAppName;    
        #    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #    proxy_set_header Host $http_host;
        #    proxy_set_header X-Real-IP $remote_addr;
        #    proxy_set_header X-Forwarded-Proto https;
        #    proxy_redirect off;
        #    proxy_connect_timeout      240;
        #    proxy_send_timeout         240;
        #    proxy_read_timeout         240;
        #    if ($http_cookie ~* "jsessionid=([^;]+)(?:;|$)") {
        #        set $co "jsessionid=$1";
        #    }
        #    proxy_set_header Cookie "$co";            
        #}
    }    
}

Monday, March 28, 2016

Eclipse is too big under Gnome (Fedora 23)

To make eclipse looks more nicer (similar look as on Windows machines) perform following steps:
  1. Create new eclipse launcher and pass GTK version 2 as parameter
    [Desktop Entry]
    Encoding=UTF-8
    Name=Eclipse IDE
    Exec=/opt/eclipse.4.5.2/eclipse --launcher.GTK_version 2
    Icon=/opt/eclipse.4.5.2/icon.xpm
    Type=Application
    Categories=Development;
    
  2. Create configuration file ~/.gtkrc-2.0 with following content:
    style "gtkcompact" { 
      font_name="Sans 8"
      GtkButton::defaultborder={0,0,0,0} 
      GtkButton::defaultoutsideborder={0,0,0,0} 
      GtkButtonBox::childminwidth=0 
      GtkButtonBox::childminheigth=0 
      GtkButtonBox::childinternalpadx=0 
      GtkButtonBox::childinternalpady=0 
      GtkMenu::vertical-padding=1 
      GtkMenuBar::internalpadding=0 
      GtkMenuItem::horizontalpadding=4
      GtkToolbar::internal-padding=0 
      GtkToolbar::space-size=0 
      GtkOptionMenu::indicatorsize=0 
      GtkOptionMenu::indicatorspacing=2 
      GtkPaned::handlesize=4 
      GtkRange::troughborder=0 
      GtkRange::stepperspacing=0 
      GtkScale::valuespacing=0 
      GtkScrolledWindow::scrollbarspacing=0 
      GtkExpander::expandersize=10 
      GtkExpander::expanderspacing=0 
      GtkTreeView::vertical-separator=0 
      GtkTreeView::horizontal-separator=0 
      GtkTreeView::expander-size=8 
      GtkTreeView::fixed-height-mode=TRUE 
      GtkWidget::focuspadding=1 
    } 
    class "GtkWidget" style "gtkcompact"
    
    style "gtkcompactextra" { 
      xthickness=2 ythickness=2 
    } 
    class "GtkButton" style "gtkcompactextra"
    class "GtkToolbar" style "gtkcompactextra"
    class "GtkPaned" style "gtkcompactextra"
    

Thursday, January 21, 2016

How to check your motherboard model under windows

wmic baseboard get product,Manufacturer,version,serialnumber

Sunday, December 06, 2015

Apache Directory (DS) systemd.service

Place following file into /usr/lib/systemd/system/apacheds.service
# Systemd unit file for ApacheDS instances.

[Unit]
Description=Apache DS LDAP server
After=syslog.target network.target

[Service]
Type=forking
ExecStart=/opt/apacheds-2.0.0_M20/bin/apacheds start default
ExecStop=/opt/apacheds-2.0.0_M20/bin/apacheds stop default
SuccessExitStatus=143
User=apacheds
Group=apacheds

[Install]
WantedBy=multi-user.target
Then execute:
systemctl enable apacheds
systemctl start apacheds

Thursday, October 01, 2015

How reliable is your PC

Thanks to the research done by Bianca Schroeder, Eduardo Pinheiro and Wolf-Dietrich Weber about errors that occur in DRAM memory, now we know that it is possible a single machine to have 48621 errors (correctable errors) per year. Roughly this makes 133.20 (48621 / 365) errors per day or 5.55 errors per hour.
The research is based on DRAM memory equipped with ECC (Error-correcting code). Most home/office PCs don't use ECC, so those errors are not detected and cause software failure (like infamous blue screen of death)

Thursday, September 24, 2015

Windows update error 8024402C

When windows update gives error 8024402C, and the machine is not managed by WSUS and has internet connection, the problem could be solved by executing following command line:
netsh winhttp reset proxy

Friday, August 14, 2015

Updating to Windows 10 when having GRUB 2 bootloader installed in MBR.



Usually when having dualboot of Windows and Linux the GRUB 2 bootloader is installed in MBR. When trying to update to Windows 10 it fails with the following error "We Can't Tell if your PC has enough space to continue".
Well the solution for updating to Windows 10 is simple - restore the hardisk Master Boot Record (MBR) using Windows installation disc (it can be also created via Microsoft's MediaCreationTool - the same tool used for updating to Windows 10. Just on the first screen choose not to update, but "Create installation media for another PC" and write it to DVD/USB).
Boot from the Windows installation DVD/USB and follow instruction until screen that allows you to install windows or "Repair your computer". Choose to "Repair your computer" / "Troubleshoot" / "Advanced options" / "Command prompt"
Execute following command:
bootrec.exe /fixmbr
Reboot and start the update process again. Now the update should be successful.
Now Windows boots successfully but Linux is no longer accessible. One way to make Linux bootable again is to use Windows bootloader to load Linux. I prefer this method because I don't want to face any future problems with windows updates.
We need a copy of the GRUB2 exported as file. For that reason we will install GRUB on Partition Boot Record (PBR) and copy the boot sector to file. First we must access the installed Linux partitions. Create a "Live CD" on DVD/USB and boot from it. The from the shell mount your existing linux installation. Let's assume that /dev/sda3 is the linux boot partition, /dev/sda4 is the root partition. Now mount the volumes:
mount /dev/sda4 /mnt
mount /dev/sda3 /mnt/boot
mount --bind /dev /mnt/dev
mount --bind /proc /mnt/proc
mount --bind /sys /mnt/sys
Optionally you may mount home directory
mount /dev/sdaX /mnt/home

Now do chroot:
chroot /mnt
Reinstall grup 2 on boot partition
grub2-install /dev/sda3
You may receive following error:
"warning: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and their use is discouraged.
error: will not proceed with blocklists"
Then just use --force
grub2-install --force /dev/sda3
Once the installation complets create a dump of the bootsector:
dd if=/dev/sda3 of=/tmp/linux.bootsector.bin bs=512 count=1
copy the /tmp/linux.bootsector.bin  to some partition accessible by Windows.
mkdir /mnt/c
mount /dev/sda2 /mnt/c
cp /tmp/linux.bootsector.bin /mnt/c
umount /mnt/c
Now reboot and start Windows and we need to create a new BCD entry for Linux
Open administrative command prompt (right click on "command prompt" and choose run as administrator)
bcdedit /create /d “Linux” /application BOOTSECTOR
The command will return GUID e.g. {5474794d-1fe8-4008-a0ae-d10210214f2a}
That GUID will be use in next commands.
Configure new BCD entry's partition and path to the location where linux.bootsector.bin is copied
bcdedit /set {5474794d-1fe8-4008-a0ae-d10210214f2a} device partition=C: 
bcdedit /set {5474794d-1fe8-4008-a0ae-d10210214f2a}  PATH \linux.bootsector.bin
Then configure the new entry to be shown last, and the OS selection menu timeout to be 5 seconds.
bcdedit /displayorder {5474794d-1fe8-4008-a0ae-d10210214f2a}  /addlast
bcdedit /timeout 5
Reboot and now you will be able to boot either Windows or Linux.

Tuesday, August 04, 2015

Windows 10/8/7/Vista administrative shares are not accessible (from linux / windows)

The information is based on Access Denied Trying to Connect to Administrative Shares C$, D$ etc.

Typical error is :

mount -t cifs -o username=superman,password=secret //192.168.22.14/c$ /mnt/c
mount error(13): Permission denied
Refer to the mount.cifs(8) manual page (e.g. man mount.cifs)
The reason is that described in KB951916 Microsoft introduced as part of UAC a little known feature called “UAC remote restrictions”. It filters the access token for connections made with local user accounts or Microsoft accounts (the latter typically have the format MicrosoftAccount\EMailAddress). In other words it removes the SID for “Administrators”. Connections made with domain accounts remain unchanged. From KB951016:
If the user wants to administer the workstation with a Security Account Manager (SAM) account, the user must interactively log on to the computer that is to be administered with Remote Assistance or Remote Desktop, if these services are available.
UAC remote restrictions can be disabled by setting the DWORD registry value LocalAccountTokenFilterPolicy to 1:
Key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
Value: LocalAccountTokenFilterPolicy
Data: 1 (to disable, 0 enables filtering)
Type: REG_DWORD (32-bit)
Reboot is not required on Windows 8/10

Thursday, July 23, 2015

OpeneElec Kodi hacking - creating music catalog

Systemd CIFS mount

/storage/.config/system.d/storage-music-rock.mount
[Unit]
 Description=cifs mount script
 Requires=network-online.service
 After=network-online.service
 Before=kodi.service

 [Mount]
 What=//192.168.0.31/MusicRock
 Where=/storage/music/rock
 Options=username=myusername,password=mypassword,rw
 Type=cifs

 [Install]
 WantedBy=multi-user.target
Important: this file must be renamed to mountpoint.mount where mountpoint, is the FULL path where the share will be mounted. Slashes "/" MUST BE REPLACED with dashes "-" with .mount as extension. This means, if we want mount to "/storage/music/rock" (see above "Where=/storage/music/rock") then this file must be renamed to 'storage-music-rock.mount'. This is only for the filename! not for the What= and Where= sections!

Script that maps file by the first two letters

/storage/.config/create_symb_links.sh chmod +s /storage/.config/create_symb_links.sh
#!/bin/bash
displayUsage() { 
  echo "Scans source directory and create symbolic links based on the file first two letters" 
  echo -e "\nUsage:\n$0 [src-dir] [links-dir]\n  src-dir\tsource directory to be scanned\n  links-dir\tfull path to target directory where symbolic links will be created\n\n" 
  echo -e "e.g.:\n $0 /storage/music/rock /storage/music/rock_links/\n\n"
  echo -e "Let's have 3 files:\n    /storage/music/rock/rock1\n    /storage/music/rock/rock2\n    /storage/music/rock/metal\n"
  echo -e "then inside /storage/music/rock_links/ you will have following files:\n"
  echo -e "    /storage/music/rock_links/RO/rock1\n    /storage/music/rock_links/RO/rock2\n    /storage/music/rock_links/ME/metal\n"
} 


if [[ -z $1 ]]; then
  displayUsage
  exit 1 
fi

if [[ -z $2 ]]; then
  displayUsage
  exit 1 
fi

dir=$1
links=$2
currdir=`pwd`

rm -Rf $links

cd $dir

mkdir -p $links
for f in *
do 
  prefix=`echo $f | cut -c 1,2 | tr [:lower:] [:upper:]`
  mkdir -p $links/$prefix
  ln -s "$dir/$f" "$links/$prefix/$f"
done

cd $currdir

Service for creating music catalog

/storage/.config/system.d/catalog-music-rock.service
[Unit]
Description=Create musics catalog
Requires=storage-music-rock.mount
After=storage-music-rock.mount
Before=kodi.service

[Service]
Type=oneshot
ExecStartPre=/bin/bash -c 'echo "Creating music catalog ..."'
ExecStart=/bin/bash -c '/storage/.config/create_symb_links.sh  /storage/music/rock /storage/music/rock_links'
StandardOutput=tty

[Install]
WantedBy=multi-user.target

Enabling mount and services

systemctl enable storage-music.mount
systemctl enable storage-music-rock.mount
systemctl enable catalog-music-rock.service

Friday, May 08, 2015

Glassfish 2.1: Using Local EJB interface in WAR's POJO

Base interface for local and remote interfaces

public interface HelloEjb extends Serializable {
  public String hello(); 
}

Define local interface

@Local
public interface HelloEjbLocal extends HelloEjb {
}

Define remote interface

@Remote
public interface HelloEjbRemote extends HelloEjb {
}

Define EJB implementation

//@Local(HelloEjbLocal.class) // not needed
//@Remote(HelloEjbRemote.class) // not needed
@Stateless
public class HelloEjbImpl extends HelloEjbLocal, HelloEjbRemote {
  public String hello() { return "hello world!"; }
}

Using EJB in POJO

Please note that the POJO must be called from a class that is part of the WAR (either servlet, webservice, etc.)
// Notes: POJO must be called by class from the WAR
@EJB(name="helloEjbJndi", beanInterface=HelloEjbLocal.class)
public class HelloClient {

  public HelloEjb getEjb() throws NamingException {
    final InitialContext ctx = new InitialContext();
    return (HelloEjb)ctx.lookup("java:comp/env/helloEjbJndi");
  }
}