After an installation you might find some file systems are too large, they are almost empty. When you want to use that space for another file system, here are the steps you can take:
Imagine /opt is now 10 Gb, but 1 Gb would be sufficient.
lsof /opt you will get a list of processes that currently use /opt. Stop these processes.df -h /opt or mount. In my example, I found /dev/mapper/VolGroup/opt hold files on /opt.umount /optresize2fs /dev/mapper/VolGroup/opt 1G. This frees the "right" part of the disk that LVM will un-allocate in a moment. All data from the file system is on the "left hand side".lvreduce -L 1G /dev/mapper/VolGroup-opt to shrink the logical volume. (It might warn you that you need to run e2fsck -f /dev/mapper/VolGroup-opt before you can continue.mount /opt.For /opt or any other filesystem that can easily be freed from open file handles, the above procedure works fine, but for "busy" filesystems, like /, /var, /usr, and so on, you'd have boot the machine without mounting filesystems. One way to do this is using the installation CD and starting up the "rescue" environment.
Here is a very simple stick to forward a TCP port from your local workstation to another host. Can be easy to use for debugging purposes:
mkfifo pipe ; cat pipe | nc -l 8080 | nc google.com 80 > pipe ; rm pipeWhat this one does:
1) Create a fifo (First in First out) file. This is a very simple type of file, you can put stuff in there with an output redirect (>) and get stuff out there with cat for example. It acts as a temporary buffer.
2) Open that newly created pipe. Anything that gets in, will be printed. (and forwarded in this example to "nc")
3) Open a listening port on your local workstation, listening on port 8080.
4) Open a connection to google.com, on port 80.
5) Send al the output to the earlier created pipe.
6) Remove the pipe when done.
Have a look the netcat homepage, it's a great tool!
We've covered this topic before in this story about creating an RPM from a shell script, but this information might help you better understand how to create an RPM.
So; you've found a piece of software that has no RPM? (Or; your manager tells you to install a piece of software that the development department created.)
Normally you'd use ./configure ; make ; make install, here is how to put that all in an RPM.
Prepare your rpm building environment: (DO THIS AS A USER!)
$ sudo yum install rpm-build
$ mkdir -p RPMBUILD/{BUILD,RPMS,SOURCES,SPECS,SRPMS}
$ echo "%_topdir /home/username/RPMBUILD" >> .rpmmacrosNow copy the software into that newly create structure.
$ cp software.tar.gz RPMBUILD/SOURCES/And now create a "spec file" for the software. This basically explains rpmbuild how to make the software and what to put in the RPM. This is the most "tweakable" step and might require quite some time to get right. Put this into /home/username/RPMBUILD/SPECS/software.spec:
Name: software
Version: 0.23
Release: 1
Summary: Custom software to run enterprise servers.
Group: Applications/Internet
License: GPLv2
URL: http://meinit.nl/
Source0: %{name}-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
%description
This software runs all enterprise software as a daemon. It's been developed by Me in IT consultancy.
%prep
%setup -q
%build
make
%install
mkdir -p $RPM_BUILD_ROOT/usr/local/bin
install software $RPM_BUILD_ROOT/usr/local/bin/software
%files
%defattr(-,root,root)
%doc README
/usr/local/bin/software
%clean
rm -rf $RPM_BUILD_ROOT
%changelog
* Tue Jun 15 2010 Robert de Bock <robert@meinit.nl> - 0.23-1
- Initial buildGood to know; the %install refers to the temporary environment that rpm will create when building this RPM. The %files section refers to what will end up in the RPM. They should correspond; you can't %install a whole bunch of files and only include a few in the $files part. (rpmbuild will display the missing files.
The group can be any line out of /usr/share/doc/rpm-*/GROUPS
So; you are prepared, run this command to so if you got everything correct:
$ rpmbuild -ba software.specWhen it finally builds, you'll find the rpm in /home/username/RPMBUILD/RPMS/$arch/software-0.23-1.$arch.rpm
It's quite easy to setup an iSCSI environment on Red Hat Enterprise Linux. Try this easy setup to get a better understanding of iSCSI.
Ingredients:
On the server execute these commands to setup a 100 Mb iSCSI target. This target can later be mounted on the client(s).
# yum install scsi-target-utils
# cat /etc/tgt/targets.conf
<target iqn.2010-04.nl.meinit:node1.target1>
backing-store /iscsi1.img
initiator-address 172.16.0.2
</target>
# dd if=/dev/zero of=/iscsi1.img bs=1024 count=102400
# chkconfig tgtd on
# service tgtd startNow on (all) client(s) follow these steps. (Please pay attention that only one client was give access in the configuration example above; 172.16.0.2.)
# yum install iscsi-initiator-utilsTo see what IQNs are available, run:
# iscsiadm -m discover -t sendtargets -p 172.16.0.1Login to the iSCSI target:
# iscsiadm -m node -T iqn.2010-04.nl.meinit:node1.target1 -p 172.16.0.1 -lIf that all works, you have new SCSI devices available, check dmesg and start iscsi at boot time:
# chkconfig iscsi onIn this example the iSCSI target does not have a filesystem. Create it on the client and mount it at boot time:
# fdsik /dev/sda
# mkfs.ext3 /dev/sda1
# echo "/dev/sda1 /mnt ext3 defaults,_netdev 0 0" >> /etc/fstabYou are done, but these commands are quite useful when connecting to an unknown iSCSI device.
To see more about the IQN:
# iscsiadm -m node -T iqn.2010-04.nl.meinit:node1.target1 -p 172.16.0.1So, you have written an enterprise quality shell script and would like to deploy it on serveral Red Hat based machines? Creating an RPM will make this easy to do. Here are the steps required.
1. Install rpmbuild so you may start to build your own RPMs.
2. Package your shell script into a tar.gz file and move that to /usr/src/redhat/SOURCES/
# tar -cvzf shell-script-0.1.tar.gz shell-script-0.1
# mv shell-script-0.1.tar.gz /usr/src/redhat/SOURCES/# cat /usr/src/redhat/SPECS/shell-script.spec
Summary: The do it all script. (Enterprise quality)
Name: shell-script
Version: 0.1
Release: 1
URL: http://meinit.nl
License: GPL
Group: Applications/Internet
BuildRoot: %{_tmppath}/%{name}-root
Requires: bash
Source0: shell-script-%{version}.tar.gz
BuildArch: noarch
%description
A shell script.
%prep
%setup
%build
%install
rm -rf ${RPM_BUILD_ROOT}
mkdir -p ${RPM_BUILD_ROOT}/usr/bin
install -m 755 shell-script.sh ${RPM_BUILD_ROOT}%{_bindir}
%clean
rm -rf ${RPM_BUILD_ROOT}
%files
%defattr(-,root,root)
%attr(755,root,root) %{_bindir}/shell-script.sh
%changelog
* Tue Jan 12 2010 Robert de Bock <robert@meinit.nl>
- Uberscript!# rpmbuild --bb /usr/src/redhat/SPECS/shell-script.spec# rpm -Uvh /usr/src/redhat/RPMS/noarch/shell-script-0.1.1.noarch.rpmI have been admiring the people who know how to use ranges in shell scripts. These people are faster and more fluent on the Linux command line than anybody without knowledge of ranges could be.
Here are some ranges or patters that you could use.
A sequence of characters, in this case 1 to 10, printed on one line.
$ echo "file{1..9}"
file1 file2 file3 file4 file5 file6 file7 file8 file9
$ echo file{s..z}
files filet fileu filev filew filex filey filezThe order of the range can be found in the man-page for "ascii".
A pattern that describes either a range, or a separated pattern.
$ echo file{1,2,4}
file1 file2 file4Additional information can be found in the man page of bash, under "Brace Expansion".
Apple's Time Machine works great, but restoring hidden files (files that start with a dot, like .ssh, .bashrc or .Trash) is difficult, but possible!
Time machine uses the settings as used by the Finder. So first step is to change Finders behaviour, to show hidden files. Execute this command (as a regular user) from within the Terminal.
$ defaults write com.apple.finder AppleShowAllFiles TRUE
$ killall FinderNow you should be able to see extra files in the finder, like this:
Now start Time Machine and scroll back to the date you were sure a file existed.
Restore it and to hide all these (annoying) hidden files, revert to original Finder settings:
$ defaults write com.apple.finder AppleShowAllFiles FALSE
$ killall FinderWhen you would like to retrieve the remotely configured time using SNMP and compare it to see how accurate the time is, here is a script to help you out.
This setup does not specifically require NTP to be running on the hosts that are checked, it just requires that the time is correct. Virtual machines for example are advised to have the appropriate "tools" installed to synchronize time. NTP is not desirable for virtual machines.
(Parts of the script are borrowed from http://spielwiese.la-evento.com/xelasblog/archives/27-SNMP-hrSystemDate....)
This is the graph that is created:
The script:
#!/bin/sh
# Nagios plugin to report time difference as received via SNMP compared to the local time.
# Make sure the machine this script runs on (poller/nagios host) is using NTP.
usage() {
# This function is called when a user enters impossible values.
echo "Usage: $0 -H HOSTADDRESS [-C COMMUNITY] [-w WARNING] [-c CRITICAL] [-v VERSION]"
echo
echo " -H HOSTADDRESS"
echo " The host to check, either IP address or a resolvable hostname."
echo " -C COMMUNITY"
echo " The SNMP community to use, defaults to public."
echo " -v VERSION"
echo " The SNMTP version to use, defaults to 2c."
echo " -w WARNING"
echo " The amount of seconds from where warnings start. Defaults to 60."
echo " -c CRITICAL"
echo " The amount of seconds from where criticals start. Defaults to 120."
exit 3
}
readargs() {
# This function reads what options and arguments were given on the
# command line.
while [ "$#" -gt 0 ] ; do
case "$1" in
-H)
if [ "$2" ] ; then
host="$2"
shift ; shift
else
echo "Missing a value for $1."
echo
shift
usage
fi
;;
-C)
if [ "$2" ] ; then
community="$2"
shift ; shift
else
echo "Missing a value for $1."
echo
shift
usage
fi
;;
-w)
if [ "$2" ] ; then
warning="$2"
shift ; shift
else
echo "Missing a value for $1."
echo
shift
usage
fi
;;
-c)
if [ "$2" ] ; then
critical="$2"
shift ; shift
else
echo "Missing a value for $1."
echo
shift
usage
fi
;;
-v)
if [ "$2" ] ; then
version="$2"
shift ; shift
else
echo "Missing a value for $1."
echo
shift
usage
fi
;;
*)
echo "Unknown option $1."
echo
shift
usage
;;
esac
done
}
checkvariables() {
# This function checks if all collected input is correct.
if [ ! "$host" ] ; then
echo "Please specify a hostname or IP address."
echo
usage
fi
if [ ! "$community" ] ; then
# The public community is used when a user did not enter a community.
community="public"
fi
if [ ! "$version" ] ; then
# Version 2c is used when a user did not enter a version.
version="2c"
fi
if [ ! "$critical" ] ; then
critical="120"
fi
if [ ! "$warning" ] ; then
warning="60"
fi
}
getandprintresults() {
# This converts the date retreived from snmp to a unix time stamp.
rdatestring=$( snmpget -v $version -c $community $host HOST-RESOURCES-MIB::hrSystemDate.0 | gawk '{print $NF}' )
if [ ! "$rdatestring" ] ; then
echo "Time difference could not be calculated; no time received."
exit 3
fi
rdate=$( echo $rdatestring | gawk -F',' '{print $1}' )
rtime=$( echo $rdatestring | gawk -F',' '{print $2}' | gawk -F'.' '{print $1}' )
cldate=$( echo $rdate | gawk -F'-' '{printf("%4i",$1)}; {printf("%02i",$2)}; {printf("%02i",$3)};' )
cltime=$( echo $rtime | gawk -F':' '{printf("%02i",$1)}; {printf("%02i",$2)}; {printf(" %02i",$3)};' )
rdate_s=$( date -d "$cldate $cltime sec" +%s )
ldate_s=$(date +'%s')
# If the calculated difference is negative, make it positive again for comparison.
difference=$(($rdate_s - $ldate_s))
if [ "$difference" -lt 0 ] ; then
positivedifference=$(($difference*-1))
else
positivedifference=$difference
fi
if [ "$positivedifference" -gt "$critical" ] ; then
echo "Time difference is more than $critical seconds: $difference|diff=$difference"
exit 2
fi
if [ "$positivedifference" -gt "$warning" ] ; then
echo "Time difference is more than $warning seconds: $difference|diff=$difference"
exit 1
fi
echo "Time difference is less than $warning seconds: $difference|diff=$difference"
exit 0
}
# The calls to the different functions.
readargs "$@"
checkvariables
getandprintresultsTo implement it in Nagios, add these sniplets to nagios.cfg. (or any other applicable nagios file.)
The service for a group.
define service{
hostgroup_name Servertype_Linux
service_description time
_SERVICE_ID 1856
use SNMP-time
}The service template.
define service{
name SNMP-time
service_description time
use generic-service
check_command check_snmp_time!$_HOSTSNMPCOMMUNITY$!120!60
max_check_attempts 30
normal_check_interval 5
retry_check_interval 1
notification_interval 0
register 0
}The command.
define command{
command_name check_snmp_time
command_line $USER1$/check_snmp_time -H $HOSTADDRESS$ -C $ARG1$ -c $ARG2$ -w $ARG3$
}When you are using MySQL, you will (likely) have tables that can be fragmented. In MySQL terms this is called "OPTIMIZE".
You could simply OPTIMIZE every table in every database, but during an OPTIMIZE, the tables are locked, so writing is not possible.
To minimize the time that MySQL will be locked (and results cannot be written), here is a script that checks fragmentation of every table of every database. Only if a table is fragmented, the table is OPTIMIZED.
#!/bin/sh
echo -n "MySQL username: " ; read username
echo -n "MySQL password: " ; stty -echo ; read password ; stty echo ; echo
mysql -u $username -p"$password" -NBe "SHOW DATABASES;" | grep -v 'lost+found' | while read database ; do
mysql -u $username -p"$password" -NBe "SHOW TABLE STATUS;" $database | while read name engine version rowformat rows avgrowlength datalength maxdatalength indexlength datafree autoincrement createtime updatetime checktime collation checksum createoptions comment ; do
if [ "$datafree" -gt 0 ] ; then
fragmentation=$(($datafree * 100 / $datalength))
echo "$database.$name is $fragmentation% fragmented."
mysql -u "$username" -p"$password" -NBe "OPTIMIZE TABLE $name;" "$database"
fi
done
doneResult will look something like this:
MySQL username: root
MySQL password:
...
database.cache_filter is 19% fragmented.
meinit.cache_filter optimize status OK
database.cache_page is 35% fragmented.
meinit.cache_page optimize status OK
...You may comment out that line with OPTIMIZE TABLE in it, if you are just interested in seeing the fragmentation.
I am not the first (and last) to write about carp, the failover/vip/floating-IP solution OpenBSD is using. Many articles describe this topic including a very complete answer to a frequently asked question about carp.
If you are not familiar with IP failover situations; in case of carp/pulse/HSRP/VIP, an IP "floats" between different machines. One machine actually answers request to received packets, so this is an solution that knows of a MASTER of ACTIVE node .
A CARP interface (which is not physical) is bound to a physical interface. The physical interface advertises statuses so other CARP interfaces know about each other.
You can bind almost any service to a CARP interface, some examples are:
Services that store data/stadia locally are not very suitable for a CARP solution. Examples are: DHCP (because leases are stored localy), MySQL/PostgreSQL (because data is stored on a physical local storage) and SSH (because you can never be sure what machine you are connecting to.
Here is how to set it up. On both boxes add a file /etc/hostname.carp0 with this content:
inet 192.168.1.123 255.255.0 192.168.1.255 vhid 1 pass SeCrEt carpdev em0Remember to activate the interface like this: (All your network cards will be (re-) configured!)
# sh /etc/netstartIn this case, 192.168.1.123 is the floating IP address and em0 is the physical device that carp0 is running on. Be aware that the other server's carpdev should be connected to the same LAN.
Now that this is done, you may access services on the newly created CARP device's IP address. You may also specifically bind applications to only the CARP device.
You may check the status using ifconfig: (Please not the "carp: MASTER" part, it tells you this machine is the master, all others are "BACKUP".)
# ifconfig carp0
carp0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
lladdr 00:00:5e:00:01:02
priority: 0
carp: MASTER carpdev em0 vhid 1 advbase 1 advskew 0
groups: carp
inet6 fe80::200:5eff:fe00:102%carp0 prefixlen 64 scopeid 0x5
inet 192.168.1.123 netmask 0xffffff00 broadcast 192.168.1.255One limitation I found; you can not run dhclient on a carp interface, you will need to assign an IP address to the carp device. Please be aware that this would be a very odd setup; DHCP in a failover interface...