2012-04-15

Using GNOME Terminal Custom Commands

There are numerous terminal session managers and profile managers, etc... for use by people [typically network and system administrators] who have to SSH or telnet to lots of hosts.   But most of these aren't packages or very well maintained - fortunately there is an almost stealth solution built into the familiar gnome-terminal application.
Multiple profiles can be created in gnome-terminal and profiles can be assigned to "Run a custom command instread of my shell";  this command can be anything.  So that profile can automatically telnet or SSH to another host, potentiall even launch an application on that host (such as firing up GNU screen).

The defined profiles are conveniently available in "Files" / "Open Terminal" and "File" / "Open Tab" menu.  Simply create a profile for each host or device that you typically jump on to. If SSH is in use the automatic tie-in to the GNOME passphrase and keyring will kick in.
Generally you don't want a terminal emulator to grab your keystrokes - you want them to go to the application or session.  Under gnome-terminal's "Edit" / "Keyboard Shortcuts" you can enable F10 to activate the ring-menu which will allow you to conveniently navigate to profiles using just the keyboard.

2012-04-14

Permission Denied on rpc_pipefs

On some openSUSE / SuSE hosts performing a "df" as a non-root users completes but ends with an error message of:
df: `/var/lib/nfs/rpc_pipefs': Permission denied
Text1: df error message for non-root users.

Note that this isn't a box with a mounted NFS volume but a box which is exporting an NFS volume; however, NFS is still an active subsystem.  This behavior is a bug (Bug#675385) that has since been closed. But if you can't perform updates quite yet and this message irritates you the work around is simple:
sudo chmod 711 /var/lib/nfs
Text2: Workaround
 The package related to this issue is "nfs-utils".

2012-04-13

A JSONDateTime TypeDecorator

JSON doesn't provide a date or date-time construct;  therefore every application is burdened with implementing a solution of it's own for receiving date-time information over the wire.  On common issue receiving JSON and serializing that data into some type of database - but the database knows the value is a date-time and you want to be able to perform date-time like operations on the value (locally).
Fortunately if your database is accessed via an SQLAlchemy ORM you can out-source this deserialization of the the values into your ORM by creating a TypeDecorator that wraps the datetime value and knows how to recognize and parse date-time values.
This example will allow an actual date-time value to be assigned to the attribute, or a 19 or 16 character string, or a NULL (None).  Conversion happens automatically when the value is assigned, but when the value is accessed an actual datetime is always seen.
from datetime import datetime
from sqlalchemy import TypeDecorator
from sqlalchemy.types import DateTime

class JSONDateTime(TypeDecorator):
    """ Allow storing a string into a datetime value, this allows 
        for automatically conversion of the JSON date strings into 
        date values"""
    impl = DateTime

    def __init__(self, *arg, **kw):
        TypeDecorator.__init__(self, *arg, **kw)

    def process_bind_param(self, value, dialect):
        if value:
            if isinstance(value, basestring):
                if (len(value) == 19):
                    return datetime.strptime(value, '%Y-%m-%dT%H:%M:%S')
                elif (len(value) == 16):
                    return datetime.strptime(value, '%Y-%m-%dT%H:%M')
                elif (len(value) == 0):
                    return None
            elif isinstance(value, datetime):
                return value
            raise Exception('Cannot store value "{0}" as
DateTime'.format(value))
        return None

# Create a class/table

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class LogEntry(Base):
    __tablename__ = 'logentry'
    ...
    actiondate = Column(JSONDateTime)
    ...
Text1: A TypeDecorator class for automatically converting string datetime representations to their datetime values; and a snippet of a table utilizing the new type.

One possible improvement is to make sure to assign a time-zone to the date value as comparing zoned and nieve datetime values will raise an exception.  But to do that you need to know the timezone you expect the JSON values to represent (in most cases this isn't present in the date-time string representation). The Python datetime's replace(tzinfo={tzinfoclass}) method is used to assign time zone information to a value. [Note: time zone information in Python.... not especially graceful or fun].

2012-04-11

Using Local Update Publisher; WSUS, but for you.

One of my colleagues has published an excellent and comprehensive article about using Local Update Publisher,a project hosted at SourceForge, that enables using your local Windows Update Services to distribute other and custom software. For example, your workstations can get deployments and updates of FireFox, Java, Flash, LibreOffice, etc... through the same mechanism used to stay up-to-date with Microsoft products.  LUP is a powerful tool for steamlining the managemento third-party software on you Microsoft Windows workstations;  if you've got lots of workstations be sure to check it out.

2012-04-08

zyppering from 11.4 to 12.1

It came time to upgrade my home server from openSUSE 11.4 to openSUSE 12.1.  Everything works fine under 11.4;  the only reason for the upgrade was to stay current.  So the simplest way to perform an in-place upgrade is to zypper dup.


Step#1) Disable all your existing repositories.
zypper modifyrepo --all --disable

Step#2) Add the 12.1 repositories.

zypper ar --name "openSUSE-12.1 OSS" \
  http://download.opensuse.org/distribution/12.1/repo/oss/ \
  repo-12.1-oss
zypper ar --name "openSUSE-12.1 Non-OSS" \
  http://download.opensuse.org/distribution/12.1/repo/non-oss/ \
  repo-12.1-non-oss
zypper ar --name "openSUSE-12.1 Updates" \
  http://download.opensuse.org/update/12.1/ \
  repo-12.1-update

Step#3) Deal with third-party repositories.
Check what third-party repositories you've added and configure the 12.1 equivalent of those.  To do this just list the URI's of the currently configured repositories, remove the 11.4 versions, and re-add them replacing the 11.4 in the URI with 12.1.  gedit search-n-replace is a handy way to pull that off. 

zypper lr --uri
Text: List the configured repositories and show their URIs.

I have the Packman, libdvdcss, Mono:Community, and Database repositories in addition to the standard repos.

zypper rr "Packman Repository"
zypper rr "libdvdcss repository"
zypper rr "openSUSE BuildService - Mono:Community"
zypper rr "openSUSE BuildService - Database"
zypper ar  \
  http://download.opensuse.org/repositories/server:/database/openSUSE_12.1 \
  "openSUSE BuildService - Database"
zypper ar \
  http://download.opensuse.org/repositories/Mono:/Community/openSUSE_12.1/ \
  "openSUSE BuildService - Mono:Community"
zypper ar \
  http://opensuse-guide.org/repo/12.1 \
  "libdvdcss repository"
zypper ar \
  http://packman.inode.at/suse/openSUSE_12.1/ \
  "Packman Repository"
Text: Remove the third-party and secondary repositories.  Then add the 12.1 versions.

Step#4) Refresh the repository information

zypper refresh

Step#5) Do the in-place distribution upgrade.
I prefer to do this in the download-all-required-packages-first mode so that a network error can't break the upgrade while it is in progress.  But if you are feeling brave or have really limited disk space you can run the "dup" without any options and packages will be retrieved on-demand.
zypper dup --download "in-advance"
Have a beverage
Update 2012-04-13: A zypper guru has informed me that the --download "in-advance" is the default behavior in recent versions; possibly even in 11.4.

Step#6) Reboot.

You are done!  Your box will come back up running openSUSE 12.1.  Enjoy.