Tuesday, November 19, 2013

Creating an LVM Volume on EBS with XFS

Well that's mouth full.. I wanted to add some storage to a VM but wanted to be able to add to it later if I got to that point. So, I attached a 100G EBS volume, and here's how I formatted it. It's EBS as the physical volume, then LVM formatted as XFS. You can attach another EBS volume to this VM, then add it to the volume group later, striped for increased capacity. Anyway, here's how it's done:
rpm -q xfsprogs &> /dev/null || yum -y instal xfsprogs
mkdir /export
pvcreate /dev/vdb
vgcreate VolGroup_EBS /dev/vdb
lvcreate -I 2M -l 100%FREE -n export VolGroup_EBS
mkfs.xfs /dev/mapper/VolGroup_EBS-export
mount /dev/mapper/VolGropu_EBS-export /export/
Finally, add this to /etc/fstab to get it mounted when your system boots:
/dev/mapper/VolGroup_EBS-export /export  xfs defaults 1 1

Friday, October 4, 2013

Multi Hop SSH SOCKS Proxy

From a corporate network I had a need to jump to one system, and through it to another in order to have an open web proxy to another 'internal' network - or in this case it was a lab network where I had to hit a openstack Horizon dashboard. It's a somewhat simple concept and I was sure SSH could do it but I had some trouble figuring out how. The scenario looks like this:
my macbook -> ssh server <- INTERNET -> second-ssh-server -> browse internal network
Note that the second ssh server was running sshd on port 22000, you probably don't need that. The command I came up with to accomplish this was:
ssh -t -t -v -L9999:localhost:9932 root@ssh-server ssh -t -D 9932 root@second-ssh-server -p 22000
A whole blog-post for one command? Yes, it was that cool!

Monday, June 24, 2013

Find the Fastest Mirror in Bash

I needed a script that would determine the fastest mirror in a list of addresses. In this example I'm using the mighty 'www.google.com' and port 80 but it's obviously configurable. I also needed to use nano seconds rather than seconds because all the results (for google) came back in less than 1 second. It should actually be a bash function but I'll leave that to you, fine reader. You're welcome!

mirror='www.google.com'
port='80'
iplist=()

for ip in $(dig $mirror A | perl -lane 'print $1 if (/A\s+(.*?)$/)')
do
   # Give me a resonable starting point (Using epoch in nano seconds).
   a=$(($(date +'%s * 1000 + %-N / 1000000')))
   nc -w 2 -z $ip $port &> /dev/null &
   b=$(($(date +'%s * 1000 + %-N / 1000000')))
   msec=`expr $b - $a`
   iplist+=("$msec $ip")
done

# Grab the fastest one..
fastest=$(for a in "${iplist[@]}"; do echo "$a"; done | sort -n | head -1 | awk '{print $2}')

echo $fastest

Thursday, July 5, 2012

sshwatch using geoiptool.com

I've written a script called 'sshwatch' that will process the default /var/log/secure file, associate the folks that have logged in against a a geoip lookup (using geoiptool.com). The idea is that you should be wary of people logging in from countries that are not expected. It will only look up each IP address once, so if you have multiple logins from the same IP, we only do a single geoip lookup. If you put this script in /etc/cron.daily/sshwatch - you'll get an e-mail each night about who's been on your box. I think it only works on RHEL and CentOS right now. Enjoy:
#!/usr/bin/perl
# Send a little report of who's been loggin in and from where.
# Joey 

use strict;
my %userblob;
$|++;

for (`cat /var/log/secure*`) {

   if (/Accepted/) { # Somebody logged in..

      my ( $user, $ip) = ( $1, $2 ) if (/for (.*?) from (.*?) /);
      $userblob{$ip}->{'IP'} = $ip;

      unless ( $userblob{$ip}->{'COUNTRY'} ) {
         $userblob{$ip}->{'COUNTRY'} = get_country($ip);
      }

      my $seen;
      for ( @{$userblob{$ip}->{'USER'}} ) {
         $seen ++ if ( $_ eq $user );
      }
      push @{$userblob{$ip}->{'USER'}}, $user unless ($seen)
   }
}

my @mail;
while ( my ($ip, $ref) = each %userblob ) {
   push @mail, "$ip :: $ref->{'COUNTRY'} :: @{$ref->{'USER'}}\n";
}

send_mail(@mail);

sub get_country() {

   my $ip = shift;
   print "Looking up: $ip: ";
   my $url = "http://www.geoiptool.com/en/?IP=$ip";
   my $data = `GET "$url"`;
   my $country = $1 if ( $data =~ /Country:.*\n.*\> (.*?)<\/a/m );
   print "$country\n";

   return $country if ($country);
   return undef;
}

sub send_mail() {

   my @body = @_;

   open  MAIL, "|/usr/sbin/sendmail.postfix -t";
   print MAIL "to: your.e-mail\@domain.com\n"
            . "from: your.mama\@domain.com\n"
            . "Subject: SSHWatch Report\n\n";

   map { print MAIL "$_" }@body;
   close(MAIL);
}


Friday, November 25, 2011

Linux: Splitting a Large File into Small Files

Recently I was trying to transfer a large ISO file across a horribly unstable VPN. The transfer would fail at various amounts of transfer percentages. So, I thought I'd best split the file up into 10MB chunks, then rsync those over and stitch it back together.

That way if it failed 90% of the way through, I wouldn't have to resend all the data, just that last 10%. The way I managed to do this, was to:

split --bytes=10m file.iso file_part 

What happens now is, you have a bunch of 10MB files called

file_partaa
file_partab
flie_partac
file_partad
...

So, just rsync all those files to the destination:

rsync -e ssh -a --progress file_part* user@desination.host.com:

When that completes, login to the remote host and put them back together:

cat file_part* > orig_file.iso


Done and done.

Tuesday, April 5, 2011

Gluster Setup in the Cloud: Simple, Easy

Here, I'll spin up two instances and configure distributed, replicated storage between them. I'll do two instances but I've actually done it for up to six instances. I have no idea how far it would scale but I'm guessing 30 or more would work fine using this method.

First I fired up two CentOS 5 instances which will be talking to each other over the private network. I'll name them node-1 and node-2 and add entries for both to /etc/hosts, like so:
10.19.128.5             node-1
10.19.128.6             node-2

They are in the same security group, so they can see each other. After you add the entries, ping the other side, like this:

[root@node-1 ~]# ping node-2
PING node-2 (10.19.128.6) 56(84) bytes of data.
64 bytes from node-2 (10.19.128.6): icmp_seq=1 ttl=64 time=0.140 ms
64 bytes from node-2 (10.19.128.6): icmp_seq=2 ttl=64 time=0.138 ms

--- node-2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.138/0.139/0.140/0.001 ms


Next, grab and install the software:
wget http://download.gluster.com/pub/gluster/glusterfs/LATEST/RHEL/glusterfs-core-3.1.3-1.x86_64.rpm
wget http://download.gluster.com/pub/gluster/glusterfs/LATEST/RHEL/glusterfs-fuse-3.1.3-1.x86_64.rpm

rpm -Uvh gluster*.rpm
rm gluster*.rpm


Then, load the fuse module:
modprobe fuse

Then, start glusterd
/etc/init.d/glusterd start

Pick some directories to use, in this case, gluster will use /export/queue-data and you and your apps will use /queue. So, don't every access files in /export/queue-data, gluster owns that directory:

mkdir /queue /export/queue-data

Setup the clients so they can see/talk to each other, run this on each system. From node-1:
[root@node-1 ~]# gluster peer probe node-2
Probe successful

[root@node-2 ~]# gluster peer probe node-1
Probe successful

Next, create your directories on both systems:
[root@node-1 ~]# mkdir -p /queue /export/queue-data/
[root@node-2 ~]# mkdir -p /queue /export/queue-data/

Now, create your volume:
[root@node-1 ~]# gluster volume create queue-data replica 2 node-1:/export/queue-data node-2:/export/queue-data
Creation of volume queue-data has been successful. Please start the volume to access data.

Ready to start the volume export:
[root@node-1 ~]# gluster volume start queue-data
Starting volume queue-data has been successful

To manually mount the volume, run:
[root@node-1 ~]# mount -t glusterfs 127.0.0.1:queue-data /queue

You can see that it's been mounted here:
[root@node-1 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             2.0G  1.5G  445M  77% /
/dev/sda2             7.9G  152M  7.4G   2% /opt
none                  256M     0  256M   0% /dev/shm
glusterfs#127.0.0.1:queue-data
                      2.0G  1.5G  445M  77% /queue


To mount it automatically on boot, run:
[root@node-2 ~]# echo "127.0.0.1:queue-data    /queue     glusterfs defaults,_netdev 0 0" >> /etc/fstab
[root@node-2 ~]# mount -a

If you're doing something different and want to be able to run VM's off your glusterfs, add this to fstab:
127.0.0.1:queue-data          /queue                   glusterfs direct-io-mode=disable,_netdev 0 0


And you can see that on node-2 it's also been mounted:
[root@node-2 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/sda1             2.0G  1.5G  445M  77% /
/dev/sda2             7.9G  152M  7.4G   2% /opt
none                  256M     0  256M   0% /dev/shm
glusterfs#127.0.0.1:queue-data
                      2.0G  1.5G  445M  77% /queue

Now, let's make sure it works. I'll create a file on node-1 and then make sure it exists on node-2:

[root@node-1 ~]# cd /queue && dd if=/dev/zero of=output.dat bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB) copied, 0.572936 seconds, 18.3 MB/s

And, here I see it on node-2:
[root@node-2 ~]# ls -al /queue
total 10276
drwxr-xr-x  2 root root     4096 Apr  5 12:49 .
drwxr-xr-x 25 root root     4096 Apr  5 12:43 ..
-rw-r--r--  1 root root 10485760 Apr  5 12:49 output.dat

And, there you have it. If you require iptables rules, which I don't because I'm already behind ec2's ACL's, add something like this to node-1 and changing the IP for node-2:
# /etc/sysconfig/iptables
-A INPUT -m state --state NEW -p tcp --dport 24007 --source 10.19.128.6 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 24008 --source 10.19.128.6 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 24009 --source 10.19.128.6 -j ACCEPT
-A INPUT -m state --state NEW -p tcp --dport 24010 --source 10.19.128.6 -j ACCEPT

You could also just do something like this:
A INPUT -m state --state NEW -p tcp --dport 24007:24010 --source 10.19.128.6 -j ACCEPT

Sunday, January 9, 2011

Ruby and Rails and MySQL and Apache and Passenger and Git: Install on CentOS 5

My New Years resolution was to learn ruby on rails, the popular web application framework. It just so happens I've been assigned a ruby project at work. Go figure..

I've been watching some screen-cast stuff my buddy at Pivotal lent me and the first thing to do was to install the stuff. Looks like it's pretty much dominated by people that develop on their Mac, then push apps to some public Rails hosting company. That's fine but I have a hankerin to install in my own CentOS 5 environment. It was actually a lot more tinkering than it should be, which is weird. So, I figured I'd better lay it out so I don't forget how it's done. Hopefully this'll help others. The latest version of ruby comes with ruby gems, the ruby package manager. So you don't need to install that separately.

Something that is interesting to note, Passenger is really mod_ruby - an apache module. They don't call it mod_ruby but that's what it is. Similar in theory to mod_perl and mod_php.



You'll get the latest stable ruby as of this writing (ruby-1.9.2-p136) + rails 3.0.3.

Another note, I'm using MySQL as my back end database but to do default 'bundle installs', you need sqlite so I'm installing that as well.


#

# Install deps
# Install the latest version of Ruby and Rails and Git to run in Apache + Passenger.
# Includes MySQL and sqlite.

yum -y install httpd zlib-devel curl-devel openssl-devel httpd-devel apr-devel apr-util-devel

wget ftp://ftp.ruby-lang.org//pub/ruby/1.9/ruby-1.9.2-p136.tar.gz
tar -xvf ruby-1.9.2-p136.tar.gz
cd ruby-1.9.2-p136
./configure --enable-shared --enable-pthread
make && make install
cd ext/zlib
ruby extconf.rb --with-zlib-include=/usr/include --with-zlib-lib=/usr/lib64
cd ../..
make
make install
ruby --version

# Installing sqlite
wget http://www.sqlite.org/sqlite-autoconf-3070400.tar.gz
tar -zxf sqlite-autoconf-3070400.tar.gz
cd sqlite-autoconf-3070400
./configure && make && make install


gem install rails
gem install passenger
gem install mysql -- --with-mysql-conf=/usr/bin/mysql --with-mysql-lib=/usr/lib64/mysql


wget http://kernel.org/pub/software/scm/git/git-1.7.3.2.tar.bz2
tar xvf git*.*
cd git*
make prefix=/usr/local all
make prefix=/usr/local install


# run this by hand because you have to answer some questions.
# passenger-install-apache2-module



Next, you'll want to configure a hosting environment with a custom http config:


vi /etc/httpd/conf.d/rails_app.conf

<VirtualHost *:80>
    ServerName www.domain.com
    DocumentRoot /opt/rails/myapp/public
    <Directory /opt/rails/myapp/public>
        Allow from all
        Options -MultiViews
    </Directory>
</VirtualHost>