Friday, 11 October 2013

DOS 6.22 printing to Samba fails with Path not found

My workplace wanted a NT server for DOS 6.22 clients replaced by a Samba server. No problem. Disk shares worked fine. But when it came to printing, this happened:

>net use lpt1 \\samba-server\printername
>copy con lpt1
Testing
^Z

Blah blah Path not found

I looked at the log file for the client in question and found these lines:

[2013/10/01 14:02:22.820899,3] smbd/vfs.c:905(check_reduced_name) check_reduced_name [DEV/LPT1] [/var/spool/samba]
[2013/10/01 14:02:22.820941,3] smbd/vfs.c:944(check_reduced_name) check_reduce_name: couldn't get realpath for DEV/LPT1 (NT_STATUS_OBJECT_PATH_NOT_FOUND)

Ah, was it trying to create a file called DEV/LPT1 in /var/spool/samba? But there is no subdirectory called DEV. So I did this:

# cd /var/spool/samba
# ln -s . DEV

Voila, printing worked from DOS. I can only surmise that DOS sends the whole path rather than just LPT1 to Samba or indeed any SMB server.

Hope this helps you if you need to convert any DOS clients to use Samba instead of NT.

Thursday, 5 September 2013

Dumont d'Urville time?

When adding a new entry into Google Calendar on my Android phone, I noticed it defaulted to Dumont d'Urville time (UTC+10), although Sydney/Melbourne was also offered. What?!

A search shows that this is the time zone of a French Antarctic station which happens to be in the same time zone as the Eastern Australian seaboard. When I went into settings and chose Use Home Time Zone, all was good again. Pretty bizarre but amusing bug. I'm glad my appointments are in warmer climes.

It seems somebody has hit this bug before. Maybe it's because my phone has a rather old version of Android.

Sunday, 1 September 2013

Installing phpMyAdmin 3 on RHEL/CentOS 5.9 running PHP 5.3

If you are running the PHP 5.3 (php53-*) packages on RHEL/CentOS 5.9 and try to install the phpmyadmin package from CentOS Base or RPMForge, you will get messages about installing the ancient PHP 5.1 packages. This was not what I wanted to happen, so I looked for a ready made phpmyadmin package that would work with PHP 5.3. I was prepared to install from a phpMyAdmin tarball, but I hoped to avoid that because an official package would stay up to date with patches.

It wasn't well publicised but the answer is to add the EPEL repository by downloading the epel-release RPM from here and installing that. After that you can do yum install phpMyAdmin3 (case important). This is the package you want.

Saturday, 10 August 2013

The Russians are not that interested in you(r blog)

When I started publishing on this blog and others years ago, I was initially gratified to see in the statistics referrals from certain sites. Of course, my vanity was punished when I discovered that these sites had nothing at all about my posts.

Some searching showed it's a practice called referer spam. No human has actually read your post for those hits. A web bot has fetched your page, but supplied a fake referral URL. So when you look at your statistics you think somebody has linked to you. You click on the link and the spammers get another page view.

The most blatant fake referrals had query terms promoting dubious products. The less blatant ones had query terms with a unique ID that let the site know you had clicked on the link. And serve up some spam after that. Some spammers used URL shorteners to conceal the source of the fake referral. At some point about a third of my "hits" were from Russia. I don't think I have that many readers there, even though I provide a translation button. Also it seems they have a way of detecting when a new blog has started up so they can target a fledgling blog. After I had published the last post of a travel blog, they lost interest in my blog.

What can you do about these fake hits? Basically nothing. Just ignore the fake hits in your statistics. Don't click on the links. Don't reward them with traffic.

By the way it isn't just the Russians doing it, there is one Korean site that attempts to get page views this way. Also some spammers use servers or hijacked PCs in the US to make it look like the hits came from there.

Sunday, 14 July 2013

RAID UUID != filesystem UUID

I had copied a RAID filesystem onto larger disks using a second computer and wanted to mount it on the original computer with minimal disruption. To this objective, I made the UUID of the new RAID array the same as the previous RAID using the assemble command of mdadm, like this:

mdadm -A /dev/md1 -U uuid --uuid=<old RAID UUID> /dev/sdb3 /dev/sdc3

(If the array is currently assembled, you have to disassemble it it first with mdadm -S /dev/md1)

This worked fine and I was able assemble the RAID on the second computer using the /etc/mdadm.conf from the first computer.

At the same time I decided to change to mount by UUID, so I edited /etc/fstab to look like this:

/dev/disk/by-uuid/<RAID UUID> /home xfs default 1 2

Alas when I booted, the RAID array wouldn't mount and I had to reboot in rescue mode to fix it up.

I wondered why the discrepancy between the symlink to /dev/md1 in /dev/disk/by-uuid and the RAID UUID. Eventually after some red herrings I understood. RAID UUID != filesystem UUID. They are distinct UUIDs. The filesystem UUID is that of the XFS (or ext4, btrfs, whatever) filesystem on it and is what is reported by blkid when udev runs it to populate the by-uuid directory. On the other hand the RAID UUID is what mdadm uses to match against entries in /etc/mdadm.conf when assembling the array.

The second lesson I learnt (again) is that you should not change two things in your config at once. I should have booted the machine up with /dev/md1 in /etc/fstab and then explored by-uuid later.

I could have kept the random RAID UUIDs generated by mdadm for the new disks and just run mdadm --examine --rescan > /etc/mdadm.conf in rescue mode to rebuild the metadata, but I want to be able to swap in the old RAID disk in an emergency and it's one less step to make the RAID UUIDs the same.

Thursday, 27 June 2013

A caching scheme to reduce downloads for Linux package updates

As I administer sites with a lot of (nearly) identical Linux hosts, I thought a lot about the issue of reducing the download for package updates. Even if you have unlimited data quota for your site, downloading the updates multiple times for multiple machines takes time.

I looked at various schemes suggested on the Internet. One is to set up a satellite repository. This is reliable but involves a lot of configuration. Also you may download a lot of package updates that are not used at your site.

Another class of scheme involves interposing a proxy. It could be a specialised proxy for the distro, or a general proxy like squid. This can work well but is sometimes defeated by load balancers or smart mirrors where you are not guaranteed to hit the same repository every download, as the actual repository used could vary.

Eventually I came up with a scheme that is applicable to three distros that I have tried it on: CentOS, Debian (and derivatives) and openSUSE. The key observation is that fact that the updaters in these distros have a package cache. If packages are added to the cache on the side, the updater will skip downloading them. I describe this as a caching scheme, not a proxying scheme as no change is made to the updater configuration files and normal, independent update works.

The scheme:

There are three parts to the scheme.

1. A download script runs on a designated master host. This runs during off-peak hours. We use the updater program in download but not install mode so we will only download packages we need. It's also necessary to set the repository to retain packages.

2. A synchronisation script runs on the other hosts to pull the new updates to their cache. This is run as soon as possible after the download.

3. Various utility scripts are used to fire off updates on all hosts. I make use of parallel ssh and ssh-agent to make life easy.

Let's use a concrete example to illustrate this.

CentOS:

1. Download:

The download script is this:

yum --disableexcludes=updates --downloadonly -y update

You need to install the auxiliary package yum-downloadonly. The --disableexcludes=updates is to disable the regular expressions that prevent the installation of the kernel on this host. On this host I disabled kernel updates due to the need to reboot and recompile VirtualBox modules whenever the kernel is updated, and as this is a server that engineers use constantly, I delay kernel updates until downtime can be scheduled to do them manually. Other software that may need recompilation on kernel update include proprietary video drivers.

To set the repository to retain packages, add

keepcache=1

to /etc/yum.conf

2. Synchronisation:

Next I set up a rsync server. Initially I used rsync over ssh, but this requires setting up a login account, restricted commands, etc. for security reasons. Package updates are not sensitive data so I just share the cache directory with rsyncd. Please consult your distro documentation on how to enable the rsyncd daemon. Usually it's run out of xinetd. Here is /etc/rsyncd.conf:

secrets file = /etc/rsyncd.secrets
motd file = /etc/rsyncd.motd
read only = yes
list = yes
uid = nobody
gid = nobody

[yum]
comment = YUM cache
path = /var/cache/yum
filter = + *.rpm + */ - *

Note the filter expression to share RPM files and directories but not files of other types.

The synchronisation script, call it syncfrommaster, on the other hosts is:

rsync -avi masterhost::yum /var/cache/yum

In the cron job that runs this command I insert a random delay so that the hosts don't all try to synchronise at the same time and overload the master.

sleep $(($RANDOM \% 900)); /root/bin/syncfrommaster

The % is escaped with \ in cron scripts by the way.

I arrange for this job to be run an hour after the download script.

3. Update.

You have probably noticed that it is possible that an update will be published in the time between the master pulling it down and you applying the updates. In this case each host merely downloads the package on its own, and nothing breaks. However you may wish to run a script to cause the cache to be updated and the hosts to catch up.

#!/bin/sh
yum --disableexcludes=updates --downloadonly -y update
pssh -h /root/linux-servers -P -p 1 -t -1 /root/bin/syncfrommaster

This first command is just the download script again. The second command makes use of the parallel ssh program to fire off syncfrommaster on each host. Before you run this you need to run ssh-agent bash, followed by ssh-add to make it possible to run pssh without supplying a login password for each host. This assumes have already installed ssh keys on each host.

4. Finally you can update all the hosts in one go:

pssh -h /root/linux-servers -P -p 1 -t -1 yum update -y

You need the -y as pssh cannot run interactive commands. You might want to run

yum update

on the master host first to check that the updates will go as expected.

It is possible that the master doesn't have all the packages in the union of all packages installed on all hosts. No harm done, the host that has distinct packages will download it on its own. Or you may wish to install that package on the master so the next update will be covered.

openSUSE:

1. Download:

zypper -n up -l -d

To set the repository to retain packages, run

zypper mr -k <repo>

for the repositories must be retained, usually repo-update and any extras such as packman.

2. Synchronisation:

/etc/rsyncd.conf (I only show the stanza added to the existing config file)

[zypp]
comment = Zypp archive
path = /var/cache/zypp/packages
read only = yes
list = yes

Notice that read only and list are in the zypp section. It can be either in the global or module section.

Synchronisation script:

rsync -avi masterhost::zypp /var/cache/zypp/packages

3. Update:

zypper up

With this info you can work out the catchup script and parallel ssh scripts. As in CentOS the -y flag also works to make zypper non-interactive.

Debian:

1. Download:

apt-get update; apt-get upgrade -d -y

2. Synchronisation:

/etc/rsyncd.conf:


[apt]
comment = APT archive
path = /var/cache/apt/archives
read only = yes
list = yes
filter = - lock

Synchronisation script:

rsync -avi masterhost::apt /var/cache/apt/archives

3. Update:

apt-get upgrade

and you can work out the catchup script and parallel ssh scripts. Again -y works to make apt-get upgrade non-interactive.

Notes:

To keep the explanation simpler I have not added the shell directives to redirect output to /dev/null. If cron jobs generate output, root or you will get mailed the output. This could be useful for debuging and to keep an eye on things, but gets tiresome after a while, given that this all works well and falls back to normal update if the caching is not effective. You will need 2>&1 to redirect stderr also.

You will notice that packages will accumulate in the cache after a while. While Debian commendably has apt-get autoclean, the other two RPM based distros do not have an analogous feature. You might just have a cron job remove packages older than a certain number of days.

Thursday, 13 June 2013

Install tmm, matplotlib, scipy and numpy on CentOS/RHEL 5

I hope this post saves you some searching if you have to go through the same steps as I did.

A user at this site wanted to run tmm for simulations on CentOS 5 servers.

CentOS/RHEL 5 unfortunately comes with python 2.4, too old for the required modules. Fortunately there is an easy way to install python 2.6 side by side and that is to get the python26 package from EPEL. If you do:
yum search python26
you will get a list of python26 packages. Aside from the base python26 package, I also needed python26-numpy. This will pull in any dependencies. When you have installed python26 you must remember to invoke python scripts with python26 or to edit the #! first line.

The scipy module was installed from source, that was the easiest way. Then I installed the tmm module. BTW in all the python extension installs I used python26 setup.py install rather than any package manager.

After that the test.py program in the tmm distribution ran. But my user pointed out that examples.py didn't run. This requires matplotlib. Ok, installed that from source. Now the function sample1() in examples.py ran, but generated no output. More searching showed that you have to specify the backend in ~/.matplotlib/matplotlibrc like this:

backend: TkAgg
interactive: true

(I'm leaving out some useless experiments involving the Postscript backend.) This generated an error about Tkinter not loading. I went back and looked at the setup step for matplotlib and noticed that when I ran:
python26 setup.py
it said I didn't have the Tkinter header files installed so it wasn't building the interface for the Tkinter backend. So I did yum install tk-devel, built and installed matplotlib again, and finally I got the example program to display a plot.

Whew!