Monday, 14 March 2016

Pretty JSON print of a CouchDB document

Using Python:
$ curl --silent --insecure https://user:'password'@couchdb-server:5984/database/document | python -m json.tool
Using Ruby:
$ gem install json
$ curl --silent --insecure https://user:'password'@couchdb-server:5984/database/document | ruby -rjson -n -e 'str=JSON.parse $_ ;puts JSON.pretty_generate(str)'

$ curl --silent --insecure https://user:'password'@couchdb-server:5984/database/document | ruby -n -e 'require "json" ; str=JSON.parse $_ ;puts JSON.pretty_generate(str)'

Ruby Procs and Blocks relation

#! /usr/bin/env ruby
def amethod(arg=10)
  yield 2
  arg * 3
end

def bmethod(&block)
  block.call
end

def cmethod(block)
  block.call
end

p = Proc.new { puts "I am a proc object" }





puts "Below is the output when amethod is called as ---> str = amethod(4) { |num| puts num }"
str = amethod(4) { |num| puts num}
puts "str = amethod(4) { |num| puts num  } returned ---> #{str}"

puts "====================="
puts "Below is the output when amethod is called as ---> str1 = amethod { |num| puts num } ; i.e no argument to amethod."
str1 = amethod { |num| puts num }
puts "str1 = amethod { |num| puts num  } returned ---> #{str1}"

puts "====================="
puts "Below is the output when amethod is called as ---> amethod { puts \"This output is from code block that does not have block arg.\" } ; i.e no argument to amethod,  no code block arg and return value discarded."
amethod { puts "This output is from code block that does not have block arg." }

puts "====================="
puts "Below is the output when amethod is called as ---> amethod(&p); where p = Proc.new { puts \"I am a proc object\"}"
amethod(&p)

puts "===================="
puts "Below is the output when amethod is called as ---> ret = amethod(20, &p); where p = Proc.new { puts \"I am a proc object\"}"
ret=amethod(20, &p)
puts "ret = amethod(20, &p) returned: #{ret}"

puts "===================="
puts "Below is the output when bmethod is called as ---> bmethod { puts \"This output is from code block that does not have block arg.\" }"
bmethod { puts "This output is from code block that does not have block arg." }

puts "==================="
puts "Below is the output when bmethod is called as ---> bmethod(&p); where p = Proc.new { puts \"I am a proc object\"}"
bmethod(&p)

puts "==================="
puts "below is the output when cmethod is called as ---> cmethod(p); where p = Proc.new { puts \"I am a proc object\"}"
cmethod(p)

Following is the output of above code:
Below is the output when amethod is called as ---> str = amethod(4) { |num| puts num }
2
str = amethod(4) { |num| puts num  } returned ---> 12
=====================
Below is the output when amethod is called as ---> str1 = amethod { |num| puts num } ; i.e no argument to amethod.
2
str1 = amethod { |num| puts num  } returned ---> 30
=====================
Below is the output when amethod is called as ---> amethod { puts "This output is from code block that does not have block arg." } ; i.e no argument to amethod,  no code block arg and return value discarded.
This output is from code block that does not have block arg.
=====================
Below is the output when amethod is called as ---> amethod(&p); where p = Proc.new { puts "I am a proc object"}
I am a proc object
====================
Below is the output when amethod is called as ---> ret = amethod(20, &p); where p = Proc.new { puts "I am a proc object"}
I am a proc object
ret = amethod(20, &p) returned: 60
====================
Below is the output when bmethod is called as ---> bmethod { puts "This output is from code block that does not have block arg." }
This output is from code block that does not have block arg.
===================
Below is the output when bmethod is called as ---> bmethod(&p); where p = Proc.new { puts "I am a proc object"}
I am a proc object
===================
below is the output when cmethod is called as ---> cmethod(p); where p = Proc.new { puts "I am a proc object"}
I am a proc object

Sunday, 13 March 2016

Sharing MacBook Pro's Keyboard and TouchPad with other Linux Machine

Introduction

I have a Dell Laptop (Fedora-23) connected to my Big screen TV via HDMI cable. I use Kodi to watch movies on TV. Though Kodi can be controlled via its web interface, but I wanted to control other things as well in Linux remotely via my MacBook pro. I found http://synergy-project.org/ as one of solution to this problem. Although it is an Open Source Project, they do not provide installers free of cost. So I performed following steps to build Synergy for my MacBook pro and Linux both.

Note: I tried VNC but was not happy with it.

Build Synergy for MacBook Pro:
I am running OSX 10.11.3. You may have to install XCODE. Additionally I am using HomeBrew as well.
You have to install "QT" on MacBook pro. I installed it using HomeBrew. I installed "4.8.7_1" QT.
$ brew install qt
$ brew install cmake
$ git clone http://github.com/symless/synergy
$ cd synergy

make changes to  ext/toolchain/commands1.py file as per https://github.com/symless/synergy/wiki/Compiling#Mac_OS_X_1010_and_above
I ran following commands to make relevant changes.
$ cd ext/toolchain/
$ perl -i -wnl -e 'm!(.*)elif sys\.platform == "darwin":(.*)! and print "$1if sys.platform == \"darwin\":$2" or print ' commands1.py
$ perl -i -wnl -e 'm!(.*)frameworkRootDir = ! and print "$1frameworkRootDir = \"/usr/local/Cellar/qt/4.8.7_1/Frameworks\"" or print ' commands1.py

$ cd ../../
$ ./hm.sh conf -g1 --mac-sdk 10.11 --mac-identity `hostname`
$ ./hm.sh build
$ ./hm.sh package mac
Mac package .dmg will be created. Install that .dmg file. First time it will not run and gives error.
To run it , Under system preference -> Security & Privacy -> Accessibility -> check Synergy .
Run Synergy (GUI app) and set it up as server.

Build synergy on Fedora-23
$ git clone http://github.com/symless/synergy
$ cd synergy

Follow instructions in https://github.com/symless/synergy/wiki/Compiling#Unix_Linux_Mac_OS_X (in short these consists of following steps)
$ ./hm.sh conf -g1
$ ./hm.sh build
$ ./hm.sh package rpm

RPM will be generated like following.
bin/synergy-master-beta-7a207b4-Linux-x86_64.rpm
Install above generated RPM. This Linux laptop will be client to Synergy Master running on MacBook Pro.
I use following command on my Linux Laptop to connect it to Synergy Master.
$ synergyc -f 192.168.0.7

192.168.0.7 is the IP ADDRESS of my MacBook Pro.
I usually run it in a screen session as following.

$ screen -S synergy synergyc -f 192.168.0.7
Once it is connected, MacBook Pro's mouse and keyboard can be shared in all three devices i.e (MacBook Pro, Linux Laptop and TV).

Thursday, 10 March 2016

Understanding packet traversing in IPTABLES

Introduction

when a packet goes through Linux IPTABLES firewall, it goes through various in-built chains and tables. These chains and tables together determine the fate of packet. This article does not tell what will happen to the packet, but will tell how a packet journey goes when it enters IPTABLES. in-short a packet workflow is described.


There are various article that explain these workflow very well. This article will just describe a pattern that would be easy to apply when dealing with IPTABLES.


At this point a diagram worth mentioning is https://upload.wikimedia.org/wikipedia/commons/3/37/Netfilter-packet-flow.svg


IPTABLES has defined following TABLES.
1) raw
2) mangle
3) nat
4) filter

Each table has following in-built CHAINS defined in them.
1) raw => PREROUTING, OUTPUT
2) mangle => PREROUTING, OUTPUT, INPUT, FORWARD, POSTROUTING
3) nat => PREROUTING, OUTPUT, POSTROUTING
4) filter => INPUT, FORWARD, OUTPUT

Three possible scenarios:
a) If a packet is coming from outside and destined for localhost then it will go through following chains:
1) PREROUTING
2) INPUT

b) if a packet is originating from localhost and destined to go out then it will go through following chains:
1) OUTPUT
2) POSTROUTING

c) if a packet is coming from outside and is destined for some other machine then packet will go through following chains:
1) PREROUTING
2) FORWARD
3) POSTROUTING

Note: CHAINS and TABLES written above are in order.
Now what is the pattern I am talking about:

Take first scenario (packet coming from outside and destined for localhost):
Kernel goes through each TABLE in order (written above) and it applies PREROUTING chain if found in that TABLE onto packet.
Kernel does same above scan of each table while applying INPUT chain to packet.

For each chain i.e [PREROUTING, INPUT]: (in order left to right)
  kernel looks for the chain in each table i.e [raw, mangle, nat, filter]: (in order left to right)
    and if chain is found in the table:
      then it applies the chain to packet
      else does nothing.


That means: For this scenario, kernel
1) first scans raw TABLE and finds PREROUTING chain here and applies it onto packet.
2) then it scans mangle TABLE and finds PREROUTING chain there and applies it to packet.
3) then it scans nat TABLE and finds PREROUTING chain there and applies it to packet.
4) then it scans filter TABLE but does not find PREROUTING chain here and does nothing to packet.
5) same above steps (1 - 4 ) are repeated for INPUT chain.
6) then kernel scans raw TABLE but does not find INPUT chain, so nothing happens here.
7) then kernel scans mangle TABLE and finds INPUT chain here and applies it to packet.
8) then kernel scans nat TABLE and does not find INPUT chain, so nothing happens here.
9) then kernel scans filter TABLE and finds INPUT chain here and applies it to packet.

For second scenario (packet originating from localhost and destined to go out):
For each chain i.e [OUTPUT, POSTROUTING]: (in order left to right)
  kernel looks for the chain in each table i.e [raw, mangle, nat, filter]: (in order left to right)
    and if chain is found in the table:
      then it applies the chain to packet
      else does nothing.

For third scenario (packet coming from outside and destined for some other machine):
For each chain i.e [PREROUTING, FORWARD, POSTROUTING]: (in order left to right)
  kernel looks for the chain in each table i.e [raw, mangle, nat, filter]: (in order left to right)
    and if chain is found in the table:
      then it applies the chain to packet
      else does nothing.
Above pattern can be corroborated with diagram above. You have to look only into network layer in that diagram.

Wednesday, 9 March 2016

SaltStack: Install RPMs from a list in text file

Introduction
To describe a rpm package installation in SaltStack, normally a salt formula with contain both the name of RPM package and a instruction to install it. If list of RPMS is large and requires changes quite regularly then maintaining states file would be very cumbersome. As state files are ususally yaml files, a human typo/error would be quite frequent then. I had a similar kind of issue.

Therefore I created a Salt formula that would use just a plain list of RPMS files in a text file. So I would just update that text file with the list of RPMS.

Strategy
We will create pillar data from a plain text file having list of RPM names on Salt Master. This pillar data will be exposed to agents with "pillar_rpm_packages" pillar key. Following will be the structure of pillar data that will be created.
'pillar_rpm_packages': [ 'package1==ver1.rel1.x86_64', 
                         'package2==ver2.rel2.x86_64',
                         'package3==ver3.rel2.x86_64', ]
Then we will create a salt module custmod_rpm_packages_from_list (on SaltMaster). This module will have a function called "create_packages_states". This salt module will be pushed to salt agents. Agents will call this module.function as custmod_rpm_packages_from_list.create_packages_states. This function accepts "pillar_rpm_packages" as its argument and then generates "json" formatted states of package installation.
create_packages_states function will create similar to following json structure.
{'pkg': ['installed', {'version': pack_version }]}
Please note that we wanted to have package installation states generated with version number included, so that only a specific version of RPM package can be installed not latest one.

Structure
This setup assumes that Salt is configured in Master/Agent mode.
Pillar is in following directory.
/srv/salt/baseenv/pillar/
States are in following directory.
/srv/salt/baseenv/states/
PILLAR DATA GENERATION
Our rpm list file , a text file, will be in following location.
# mkdir /srv/salt/baseenv/pillar/data
# touch /srv/salt/baseenv/pillar/data/rpm_packages.list
Following are the contents of rpm_packages.list file. Ofcourse you can add your own.
# cat /srv/salt/baseenv/pillar/data/rpm_packages.list
lsof-4.82-4.el6.x86_64
dash-0.5.5.1-4.el6.x86_64
ed-1.1-3.3.el6.x86_64
Create Pillar function.
# mkdir /srv/salt/baseenv/pillar/allrpmpackages
# touch /srv/salt/baseenv/pillar/allrpmpackages/init.sls
Following are the contents of pillar/allrpmpackages/init.sls file.
#!py
#
# This state file will just extract packages name versions and release info and create a salt compatibale data structure 
# created data structure will be : 
# config = { 'pillar_rpm_packages': [ 'package1==ver1.rel1.x86_64', 'package2==ver2.rel2.x86_64' ] }
#

import os, subprocess

def run():
  config = { 'pillar_rpm_packages': []}
  for package in open('/srv/salt/baseenv/pillar/data/rpm_packages.list'):
    package=package.rstrip()
    repo_query_command="repoquery " + package + " --qf '%{NAME}==%{VERSION}-%{RELEASE}'"
    rep_query_process=subprocess.Popen(repo_query_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    rep_query_process.wait()
    if rep_query_process.returncode == 0:
      formatted_package_name=rep_query_process.stdout.readline().rstrip()
      config['pillar_rpm_packages'].append(formatted_package_name)
  return config
/srv/salt/baseenv/pillar/top.sls will have something similar to following.
baseenv:
  '*':
    - allrpmpackages
STATES and MODULE GENERATION
Create module.
# mkdir -p /srv/salt/baseenv/states/_modules
# touch /srv/salt/baseenv/states/_modules/custmod_rpm_packages_from_list.py
Following are the contents of states/_modules/custmod_rpm_packages_from_list.py
#! /usr/bin/env python

import os, subprocess, re, os.path

packages_states = { }
def create_packages_states(pillar_key):
 for pillar_pack in __pillar__[pillar_key]:
   match_obj=re.search(r'(?P.+)==(?P.+)',pillar_pack)
   pack=match_obj.group('rpm_pack_name')
   pack_version=match_obj.group('rpm_version')
   pack_hash = { pack: pack_version } 
   packages_states[pack] = {'pkg': ['installed', {'version': pack_version }]}
 return packages_states
Now if we want to use above module to Install RPMS, then create a state file with following contents.
# touch /srv/salt/baseenv/states/install_rpm_packages.sls
states/install_rpm_packages.sls file will have following contents.
#!py
config = {  }
def run():
  config = __salt__['custmod_rpm_packages_from_list.create_packages_states']('pillar_rpm_packages')
  return config
baseenv/states/top.sls may have following contents.
baseenv:
  '*':
   - install_rpm_packages
Above code can also be found at https://github.com/spareslant/SaltStackRPMInstallFromListFormula

Non-Interactive, Non-GUI VM build using KVM/libvirtd/kickstart

Introduction:
We will build a VM using KVM/Qemu hypervisor. But we will manage this VM using libvirtd. This VM build will use a kickstart file. This kickstart file will be embedded into VM during install process.

Environment/Tools used:
Host OS is Debian Jessie (Debian-8). We will build CentOS-7.0 VM on this Debian Host. We will use
CentOS-7-x86_64-Minimal-1511.iso image stored in Host machine to build VM. 

libvirtd networking:
Please see following link for details.
http://spareslant.blogspot.co.uk/2016/02/libvirtd-netwroking.html

Activate libvirtd "default" network:
# virsh net-list --all

If above output shows that "default" network is inactive then run following command to activate it.

# virsh net-start default
Activate DHCP in "default" network.
# virsh net-update default add ip-dhcp-range '<range start="192.168.122.100" end="192.168.122.254" />' --live
Create storage file.
# qemu-img create -f qcow2 /home/testuser/Downloads/KVM_IMAGES/centos-7.qcow2 5G
Note: I created above storage file because I am using non-standard location. Above step is not required if using libvirtd defaults.

Install Virtual Machine.
# virt-install \
--name centos-vm1 \
--memory 1024 \
--cpu=host \
--vcpus 1 \
--os-type=linux \
--graphics none \
--disk path=/home/testuser/Downloads/KVM_IMAGES/centos-7.qcow2 \
--initrd-inject=/tmp/ks.cfg \
--console pty,target_type=serial \
--extra-args='ks=file:/ks.cfg console=ttyS0,115200n8 serial' \
--network=default \
--location /home/testuser/Downloads/CentOS-7-x86_64-Minimal-1511.iso
Note:
1) Please note --graphics none parameter. This is required for non-gui installation.
2) Please note "--initrd-inject=/tmp/ks.cfg" parameter. we are injecting ks.cfg file dynamically. No need of external HTTP/FTP/NFS to host ks.cfg.
3) Above command will start installation of VM non-interactively and non-GUI mode.
4) Above setup uses Virtual Private network.
5) VMs setup in this manner however can access external world. But external world cannot access them.
6) VMs setup in this manner can communicate with each other and with HOST machine as well.
7) In this setup HOST machine will have two IPs. One IP on eth0 (as usual) and other IP on virb0 bridge. Both are in different network. Hence isolating VMs network.
8) If we want HOST machine and VMs to be on same network then BRIDGE networking needs to be used.

Following is the ks.cfg file:
#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
# Use CDROM installation media
cdrom
# Use text mode install
text
# Run the Setup Agent on first boot
firstboot --disable
# Keyboard layouts
keyboard --vckeymap=uk --xlayouts='uk'
# System language
lang en_GB.UTF-8

# Network information
#network  --bootproto=static --device=eth0 --gateway=192.168.0.1 --ip=192.168.0.61 --nameserver=8.8.8.8 --netmask=255.255.255.0 --ipv6=auto --activate --hostname=centosvm1
network --bootproto=dhcp --onboot=yes

# Root password
rootpw --iscrypted $6$pDcoINZetTlq2e2S$Tjz7tBv14Mrw41paKN0O57o.7m7HNWOmIguqdLO6YAA1yrxUcl1mypt5bBKqjVuOqnlNOOoeQH9zJud6FfXcz1
# Do not configure the X Window System
skipx
# System timezone
timezone Europe/London --isUtc
user --name=ocean1 --password=$6$wTphTlXg/5nlzaNK$YoezS.sO80koCnVgyC.kOxF.t3jo0dzk9ey6ENiAPpWme9dfKTFX7ziC.oONjtAh1hDnlLLLq1j4N5YWUlcrK0 --iscrypted
# System bootloader configuration
bootloader --append=" crashkernel=auto console=ttyAMA0,115200 console=tty console=ttyS0" --location=mbr
autopart --type=plain
# Partition clearing information
clearpart --all --initlabel

%packages
@core
kexec-tools

%end

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

%post --interpreter /usr/bin/python --log=/root/post-log
import os
entirefile=open('/etc/default/grub').read()
entirefile=entirefile.replace('rhgb', '')
entirefile=entirefile.replace('quiet', '')
open('/etc/default/grub', 'w').write(entirefile)
os.system("grub2-mkconfig -o /boot/grub2/grub.cfg")

%end

Note: Please note "text" parameter used in ks.cfg file. This is for non-GUI text installation.

Build Virtual Machine Using KVM/Qemu and Kickstart

Introduction:
We will build a VM using KVM/Qemu hypervisor. This VM build will use a kickstart file. This kickstart file will be served from a web server. Instead of building a full blown web server like apache or nginx, we will build a simple HTTP server using Golang, that will serve our kickstart file.

Environment/Tools used:
Host OS is Debian Jessie (Debian-8). We will build CentOS-7.0 VM on this Debian Host. We will use
CentOS-7-x86_64-Minimal-1511.iso image stored in Host machine to build VM. Make sure Go compiler is installed.

Create Web Server:
mkdir GO_HTTP_SERVER
Create following two files inside GO_HTTP_SERVER directory
$ ls
ks.cfg serve_ks.go
serve_ks.go file:
package main
import (
  "net/http"
)

func main() {
  http.ListenAndServe(":8080", http.FileServer(http.Dir("./")))
}
ks.cfg file
#version=DEVEL
# System authorization information
auth --enableshadow --passalgo=sha512
# Use CDROM installation media
cdrom
# Use text mode install
text
# Run the Setup Agent on first boot
firstboot --disable
# Keyboard layouts
keyboard --vckeymap=uk --xlayouts='uk'
# System language
lang en_GB.UTF-8

# Network information
#network  --bootproto=static --device=eth0 --gateway=192.168.0.1 --ip=192.168.0.61 --nameserver=8.8.8.8 --netmask=255.255.255.0 --ipv6=auto --activate --hostname=centosvm1

# Root password
rootpw --iscrypted $6$pDcoINZetTlq2e2S$Tjz7tBv14Mrw41paKN0O57o.7m7HNWOmIguqdLO6YAA1yrxUcl1mypt5bBKqjVuOqnlNOOoeQH9zJud6FfXcz1
# Do not configure the X Window System
skipx
# System timezone
timezone Europe/London --isUtc
user --name=ocean1 --password=$6$wTphTlXg/5nlzaNK$YoezS.sO80koCnVgyC.kOxF.t3jo0dzk9ey6ENiAPpWme9dfKTFX7ziC.oONjtAh1hDnlLLLq1j4N5YWUlcrK0 --iscrypted
# System bootloader configuration
bootloader --append=" crashkernel=auto console=ttyAMA0,115200 console=tty console=ttyS0" --location=mbr
autopart --type=plain
# Partition clearing information
clearpart --all --initlabel

%packages
@core
kexec-tools

%end

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

%post --interpreter /usr/bin/python --log=/root/post-log
import os
entirefile=open('/etc/default/grub').read()
entirefile=entirefile.replace('rhgb', '')
entirefile=entirefile.replace('quiet', '')
open('/etc/default/grub', 'w').write(entirefile)
os.system("grub2-mkconfig -o /boot/grub2/grub.cfg")

%end
Note:
1) CentOS-7.0 minimal ISO image does not have perl packages. Therefore I have to use python for post installation task in ks.cfg file.
2) Change your encrypted password.
3) Post installation section in ks.cfg will disable "quiet" boot. That means all boot information will be displayed on console.
4) ks.cfg has kernel boot parameters so that console can be redirected.
5) It uses default network configuration provided by QEMU/KVM. (using default DHCP embedded in qemu).

Run HTTP server
$ cd GO_HTTP_SERVER
$ go run serve_ks.go

verify that webserver is running. Run following command on another terminal.
$ curl http://IPADDRESS_OF_HOSTMACHINE:8080/ks.cfg

You should see output.
Note:
1) Web server is started on port 8080
2) Use machine IP address not localhost or 127.0.0.1 because , VM will communicate with host machine for installation and it cannot communicate with host machine on 127.0.0.1.
3) When you start webserver using "go run serve_ks.go" command, it prints nothing on screen. You can stop web server just by pressing Ctrl-c.

Build VM
Create Storage File
# qemu-img create -f qcow2 centos-7.qcow2 5G
Start VM in user networking mode
# qemu-system-x86_64 -enable-kvm -cpu host -m 1024 -cdrom /home/testuser/Downloads/CentOS-7-x86_64-Minimal-1511.iso -hda /home/testuser/Downloads/KVM_IMAGES/centos-7.qcow2  -boot d
A new window will pop up with boot options. Press TAB. Some options will be visible. Append following to those options.
ks=http://IPADDRESS_OF_HOSTMACHINE:8080/ks.cfg
Once system installation is complete, run VM using following command.
Please note the omission of "-boot d".
# screen -S centos qemu-system-x86_64 -enable-kvm -cpu host -m 1024 -cdrom /home/testuser/Downloads/CentOS-7-x86_64-Minimal-1511.iso -hda /home/testuser/Downloads/KVM_IMAGES/centos-7.qcow2
Update kernel boot parameters so that console can be redirected to terminal where qemu command is fired. then run following command. (note -nographic) (attached ks.cfg has this functionality). So you do not need to manually update kernel boot parameters.
# screen -S centos qemu-system-x86_64 -enable-kvm -cpu host -m 1024 -cdrom /home/testuser/Downloads/CentOS-7-x86_64-Minimal-1511.iso -hda /home/testuser/Downloads/KVM_IMAGES/centos-7.qcow2  -nographic
Note: Please note that We started VM in a screen session so that VM console can be attached or detached easily.
We do not need to do this when VMs are build using libvirtd. libvirtd provides many functionalities .

Tuesday, 8 March 2016

Java and Ruby Inheritance Comparison

Following is a Ruby Program. This is heavily commented with reference to Java and Ruby both.
class A
  def methoda_public
    puts "Hello from methoda_public self=#{self}"
  end

  def methoda_private
    puts "Hello from methoda_private self=#{self}"
  end

  def methoda_protected
    puts "Hello from methoda_protected self=#{self}"
  end

    # 1) Java => class methods are defined using static keyword. instances can access class methods in Java.
    # 2) Ruby => class methods are actually singleton methods of class itself. (in Ruby a class is an object itself.). class methods are actually defined in
               # singleton class of "class object" and hence called as singleton methods. Only that object can call singleton method on which it is defined and none other.
               # Singleton methods are Exclusive to a single particular object only. Hence even the instances created from class A cannot access class methods.
               # derived class can invoke base class' singleton object. Again instances of Derived class cannot access singleton method defined on base class.
  def self.methoda_classmethod_public
    puts "hello from methoda_classmethod_public self=#{self}"
  end

  private :methoda_private
  protected :methoda_protected
end

class B < A
  def public_methodb_calling_private_methoda

      # 1) Java => private members are not inherited directly in derived class. So this will not work in Java.
                 # Derived class inherits base class' protected and public members. So if Base class' protected/public method access private member
                 # then Derived class can also 'work' on private member via inherited protected/public methods.
      # 2) Ruby => private members are inherited in Ruby. So this will work in ruby.
    methoda_private       

      # 1) Java => you cannot access private memebers directly in derived class. So this will not work in Java.
      # 2) Ruby => Will not work as private members must be accessed WITHOUT explicit receiver in derived class.
    #A.new.methoda_private  # A new object is created and we are trying to access its private member.  will not work.
    #self.methoda_private   # An equivalent in Java would be this.methoda_private(). But ofcourse in Java private members are not inherited so will not work.
      
      # 1) Java => Protected members can be accessed in derived class directly becuase they are inherited. So this will work.
      # 2) Ruby => Protected members are inherited in Ruby as well. So this will work.
    methoda_protected

      # 1) Java => protected memeber cannot be accessed in drived class using reference variable(i.e. by creating object).
      # 2) Ruby => This will work. But this will NOT work in Ruby also if below expression i.e. A.new.methoda_protected is called outside class B. 
    A.new.methoda_protected

      # 1) Java => A Java equivalent would be this.methoda_protected() . This will work in Java. As protected methods are inherited in Java directly. Needed verification.
      # 2) Ruby => This will work. Ruby will be calling inherited method. Java will also do the same.
    self.methoda_protected

      # 1) Java => Instance method can call static method (class method).
      # 2) Ruby => This will not work. Instance method CANNOT call class method.
    #methoda_classmethod_public

      # 1) Java => instance method can call static method (class method). In java it would be this.methoda_classmethod_public()
      # 2) Ruby => this will not work. Because inside instance method self will be referring to the instance of B. And instance of B CANNOT call
                 # singleton method of class A.
    #self.methoda_classmethod_public
  end

    # 1) Java => Both below statements are not allowed in Java. These are called outside any method definition.
    # 2) Ruby => Both below will work in Ruby. Hence class methods are inherited but only to be called by derived class itself.
               # class methods are singleton method. Normally singleton methods are called by only their own onjects.
               # But when in case of singleton methods defined on class (class methods), they can be called by dervied class also. (Not by derived class instances).
  methoda_classmethod_public
  self.methoda_classmethod_public
end

#A.new.methoda_private     # => will not work. (same as in Java)
#A.new.methoda_protected   # => will not work. (same as in Java). Compare and take a note of this expression inside class B as well.
#A.new.methoda_classmethod_public # => Will not work in Ruby but will work in Java. Java syntax would be: A a = new A(); a.methoda_classmethod_public() .

B.new.public_methodb_calling_private_methoda
B.methoda_classmethod_public  # => will work both in Java and Ruby

A Simple Vagrant Setup


Preparation:

mkdir MCOLLECTIVE_VAGRANT
cd MCOLLECTIVE_VAGRANT
vagrant init
vagrant box add puppetlabs/centos-6.6-64-nocm
modify contents of MCOLLECTIVE_VAGRANT/Vagrant file to look like below:

Single Instance Vagrantfile
$ cat Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
     config.vm.box = "puppetlabs/centos-6.6-64-nocm"
     config.vm.network "public_network"
     config.vm.hostname = "vagrant.virtual.machine"
     config.vm.provider "virtualbox" do |v|
          v.memory = 1024
          v.cpus = 1
     end
end
Multi Instance Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
     config.vm.box = "puppetlabs/centos-6.6-64-nocm"
     config.vm.network "public_network"
     config.vm.provider "virtualbox" do |v|
          v.memory = 1024
          v.cpus = 1
     end
     config.vm.define "first" do |first|
          config.vm.hostname = "first.virtual.machine"
     end
     config.vm.define "second" do |second|
          config.vm.hostname = "second.virtual.machine"
     end
end
To start Vagrant instances.
vagrant up
To login into new VM machine.
vagrant ssh
To check status
vagrant global-status
Config with autostart: false and Mix of CentOS and Debian.
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure(2) do |config|
     config.vm.box = "puppetlabs/centos-6.6-64-nocm"
     config.vm.network "public_network"
     config.vm.provider "virtualbox" do |v|
          v.memory = 1024
          v.cpus = 1
     end
     config.vm.define "first", autostart: false do |first|
          config.vm.hostname = "first.virtual.machine"
     end
     config.vm.define "second", autostart: false do |second|
          config.vm.hostname = "second.virtual.machine"
     end
     config.vm.define "debian-7.4", autostart: false do |second|
          config.vm.box = "chef/debian-7.4"
          config.vm.hostname = "debian.virtual.machine"
     end
end
Bring up only Debian machine
vagrant up debian-7.4
vagrant ssh debian-7.4
Bring up now first machine
vagrant up first
vagrant ssh first
Note: When autostart: false is configured , Vagrant machines have to be brought up manually

Tuesday, 1 March 2016

Understanding JAVA Nested Classes

class OuterClass {
    private String outerClassPrivateInstanceVar = "outerClassPrivateInstanceVar";
    public static String outerClassPublicStaticVar = "outerClassPublicStaticVar";
    public String outerClassPublicInstanceVar = "outerClassPublicInstanceVar";

    void outerClassInstanceMethod() {
        System.out.println("Inside outerClassInstanceMethod.");
    }

    static void outerClassStaticMethod() {
        System.out.println("Inside outerClassStaticMethod.");
    }

    // NON-STATIC Inner class
    class InnerClass {
        // Non-static innerClass cannot have static members. Following will not work.
        // static String InnerClassStaticVar = "InnerClassStaticVar";
        public void innerClassMethod() {
            System.out.println("Inside innerClassMethod.");
        }
        public void innerClassAccessOuterClassVars() {
            System.out.println(outerClassPrivateInstanceVar);
            System.out.println(outerClassPublicInstanceVar);
            System.out.println(outerClassPublicStaticVar);
        }
    }

    // STATIC Inner class
    static class InnerClassStatic {
        // Following is allowed in Static InnerClass but not in non-static inner class.
        static String StaticInnerClassStaticVar = "StaticInnerClassStaticVar";
        String InnerClassStaticInstanceVar = "InnerClassStaticInstanceVar";
        public void innerClassStaticMethod() {
            System.out.println("Inside InnerClassStatic.");
        }
        public void innerClassStaticAccessOuterClassVars() {
            // Following will not work. Beacuse InnerClassStatic is like static member inside OuterClass
            // and static members/methods can never access instance members.
            //System.out.println(outerClassPrivateInstanceVar);
            //System.out.println(outerClassPublicInstanceVar);

            System.out.println(outerClassPublicStaticVar);
        }
    }

    // Local Inner Class inside Instance method.
    void outerClassInstanceMethodForLocalClass() {
        // Local Inner Classes cannot be private, protected, public and static. Because inside method
        // these keywords have no sense. We don't use these words inside methods.
        class LocalClassInInstanceMethod {
            // Static members are not allowed in Local Inner classes defined inside instance method.
            // Following will not work.
            //static String LocalClassInInstanceMethodStaticVar = "LocalClassInInstanceMethodStaticVar";
            void localClassInInstanceMethod_instanceMethod() {
                System.out.println("Inside localClassInInstanceMethod_instanceMethod.");
            }
        }
        LocalClassInInstanceMethod localClassInInstanceMethodObj = new LocalClassInInstanceMethod();
        localClassInInstanceMethodObj.localClassInInstanceMethod_instanceMethod();
    }

    // Local Inner Class inside Static method.
    static void outerClassStaticMethodForLocalClass() {
        // Local Inner Classes cannot be private, protected, public and static. Because inside method
        // these keywords have no sense. We don't use these words inside methods.
        class LocalClassinStaticMethod {
            // Static members are not allowed in Local Inner classes defined inside static  method.
            // Following will not work.
            //static String LocalClassinStaticMethodStaticVar = "LocalClassinStaticMethodStaticVar";
            void LocalClassinStaticMethod_instanceMethod() {
                System.out.println("Inside LocalClassinStaticMethod_instanceMethod.");
            }
        }
        LocalClassinStaticMethod locallassinStaticMethodObj = new LocalClassinStaticMethod();
        locallassinStaticMethodObj.LocalClassinStaticMethod_instanceMethod();
    }

    // Anonymous Inner classes
    interface InnerInterface {
        void InnerInterfaceMethod();
    }
    // Anonymous inner class object defined at class member level.
    InnerInterface anonymousClassObj = new InnerInterface() {
        public void InnerInterfaceMethod() {
            System.out.println("Inside InnerInterfaceMethod.");
        }
    };
    void callAnonymousObjectMethod() {
        anonymousClassObj.InnerInterfaceMethod();
    }
    // Anonymous inner class inside instance method.
    //void anonymousInnerClassInsideMethod() {
    OuterClass  anonymousInnerClassInsideMethod() {
        OuterClass anon = new OuterClass() {
            void outerClassInstanceMethod() {
                System.out.println("Inside anonymousInnerClassInsideMethod.");
            }
        };
        //anon.outerClassInstanceMethod();
        return anon;
    }
}

public class InnerClassesTest {
    public static void main(String[] args) {
        OuterClass outerClassObj = new OuterClass();

        // Call to instance method using instance variable.
        outerClassObj.outerClassInstanceMethod();

        // Call to static method using instance variable. In Ruby there is something called self instead of static. And
        // self.outerClassStaticMethod  in Ruby is actually a singleton method defined on a "class object (OuterClass)" and in Ruby class
        // itself is an object. And singleton methods can be called by only object on which it is defined, in this case OuterClass object.
        // Hence in Ruby object created by a class cannot access class method. Following is invalid in Ruby.
        outerClassObj.outerClassStaticMethod();

        // NON-STATIC INNER CLASSES
        // Creating InnerClass object.
        System.out.println("====NON-STATIC INNER CLASSES====");
        OuterClass.InnerClass innerClassObj = new OuterClass().new InnerClass();
        innerClassObj.innerClassMethod();

        // Following will not work. outerClassPublicInstanceVar is not defined in InnerClass.
        //System.out.println(innerClassObj.outerClassPublicInstanceVar);

        innerClassObj.innerClassAccessOuterClassVars();

        // STATIC INNER CLASSES.
        // Creating Static Innerclass object. You will be using Class not object.
        System.out.println("====STATIC INNER CLASSES====");
        OuterClass.InnerClassStatic innerClassStaticObj = new OuterClass.InnerClassStatic();
        // You cannot use OuterClass object to use StaticInnerClass object. This is in contrast with creating InnerClass(non-static) object.
        // Also normally an object can access static class fields. But Following will not work.
        //OuterClass.InnerClassStatic innerClassStaticObj2 = outerClassObj.InnerClassStatic();

        // Access static inner class' static member using static inner class' object.
        System.out.println(innerClassStaticObj.StaticInnerClassStaticVar);
        // Access static inner class' static member using Classes directly.
        System.out.println(OuterClass.InnerClassStatic.StaticInnerClassStaticVar);
        // Access static inner class' instance member using static inner class' object.
        System.out.println(innerClassStaticObj.InnerClassStaticInstanceVar);

        // LOCAL INNER CLASSES
        System.out.println("====LOCAL INNER CLASSES====");
        outerClassObj.outerClassInstanceMethodForLocalClass();
        outerClassObj.outerClassStaticMethodForLocalClass();
        OuterClass.outerClassStaticMethodForLocalClass();

        // ANONYMOUS INNER CLASSES
        System.out.println("====ANONYMOUS INNER CLASSES====");
        outerClassObj.callAnonymousObjectMethod();
        // Following works because, interface InnerInterface is visible in this class as well due to default access.
        // If inner interface in made private then following will not work. Only inner interfaces can be made private.
        outerClassObj.anonymousClassObj.InnerInterfaceMethod();

        OuterClass anonymousObj = new OuterClass() {
            void outerClassInstanceMethod() {
            System.out.println("inside anonymousObjOfOuterClassSubClass Method.");
            }
            void anotherMethod() {
                System.out.println("Inside anotherMethod.");
            }
        };
        anonymousObj.outerClassInstanceMethod();
        // Following will not work. Because anonymousObj is refering to actually subclass of OuterClass (in memory). But it is declared as OuterClass.
        // That means, anonymousObj is actually a "Subclass of OuterClass" but its type is declared as OuterClass. Hence polymorphism will come in.
        // anonymousObj being declared as superclass variable will only be able to execute methods defined in super class not in sub class. Hence
        // following will not work.
        //anonymousObj.anotherMethod();

        //Following works provided relevant lines are un-commented inside anonymousInnerClassInsideMethod instance method.
        //outerClassObj.anonymousInnerClassInsideMethod();
        OuterClass out = outerClassObj.anonymousInnerClassInsideMethod();
        out.outerClassInstanceMethod();
    }
}
Compile and Output:
$ java -version
java version "1.8.0_66"
Java(TM) SE Runtime Environment (build 1.8.0_66-b17)
Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
$
$ javac InnerClassesTest.java
$ java InnerClassesTest
Inside outerClassInstanceMethod.
Inside outerClassStaticMethod.
====NON-STATIC INNER CLASSES====
Inside innerClassMethod.
outerClassPrivateInstanceVar
outerClassPublicInstanceVar
outerClassPublicStaticVar
====STATIC INNER CLASSES====
StaticInnerClassStaticVar
StaticInnerClassStaticVar
InnerClassStaticInstanceVar
====LOCAL INNER CLASSES====
Inside localClassInInstanceMethod_instanceMethod.
Inside LocalClassinStaticMethod_instanceMethod.
Inside LocalClassinStaticMethod_instanceMethod.
====ANONYMOUS INNER CLASSES====
Inside InnerInterfaceMethod.
Inside InnerInterfaceMethod.
inside anonymousObjOfOuterClassSubClass Method.
Inside anonymousInnerClassInsideMethod.