Monday Oct 19, 2009

Here's how:

# Install pkg_* tools and the 'pkgin' package manager
$ pkgadd -d http://www.netbsd.org/~sketch/TNFpkgsrc-x86.pkg all

# Add tools to PATH
$ PATH=/opt/pkg/sbin:/opt/pkg/bin:$PATH

# Update package repository (akin to 'apt-get update')
$ pkgin up

# Search for a particular package (you can use regexp) 
$ pkgin search ^ap.*python 

# Install it
$ pkgin install ap22-py25-python

# Update all packages (akin to 'apt-get dist-upgrade')
$ pkgin full-upgrade

# How many packages are available?
$ pkgin avail | wc -l
   4970

Ok, so the headline might be slightly mis-leading, this isn't really apt-get but a tool which is very similar. This is work which builds upon my previous post using pkgsrc to build binary packages on Solaris.  See http://imil.net/pkgin/ for more information on pkgin.

Hopefully this will prove really useful to people still using Solaris 10 and unable to use the new pkg(5) stuff in OpenSolaris. Please try it out and provide any feedback to pkgsrc-users@netbsd.org.  I'm hoping to keep the packages updated for the 2009Q3 branch.

Saturday Sep 12, 2009

For many years, building and installing third-party software on Solaris has been a huge pain. For people who do not use pkgsrc, that is.

Originating from the NetBSD project, pkgsrc is a source-based cross-platform package manager. If you've used FreeBSD ports, then it is very similar as it derives from the same codebase, so the basic premise is that you

$ cd /usr/pkgsrc/www/apache22
$ make package

and pkgsrc will download the source for Apache 2.2, compile it and all dependancies, install it on the local system and create a package which can be installed on other similar systems.

However, we've taken ports further and applied the NetBSD philosophy of portability, meaning that it not only works on NetBSD, but across all *BSD as well as Linux, OSX, HP/UX, AIX, IRIX, QNX, Windows (via Interix), and of course Solaris.

So while apt-get might be awesome, it only really works on Linux. FreeBSD might have way more ports than us, but only runs on FreeBSD and OSX. pkgsrc provides a consistent interface across all the platforms listed above, and in many cases provides a far superior package manager than the system provides.

Here's how I use pkgsrc on Solaris, in this specific case Solaris 10/x86. Paths are specific to my setup, you can of course change them.

Create a chroot/zone environment

I use the zones feature of Solaris 10 to ensure that all packages are built in a sandbox. This has a number of benefits:

  • The running system is unaffected by the builds, in that they are not writing to the same file system. This is good when you have misbehaving packages.
  • You can separate the build and install phases, so that you can verify all the packages have been built and are correct before starting any install/upgrade procedure
  • It's easier to catch package mistakes, e.g. unpackaged files.
  • It avoids pollution from the host environment which may produce bad packages

I wrote two scripts, create-zone for starting the zone and delete-zone for stopping and removing it. If you want to use them then there are some variables to set at the top, and you may want to scan through them for additional bits to change (e.g. create-zone copies my ssh public key which will most likely be wrong for your setup :-)

One additional piece of configuration for create-zone is an optional SMF xml file. I use this file to disable inetd inside the zone for additional security. You can do other bits if you like, or just not bother. The file should be named <yourzonename>.xml

Fetch pkgsrc

pkgsrc is developed very rapidly. Tracking nearly 9,000 pieces of third-party software means there are always many updates. Thankfully, we provide quarterly branches for people who want more stability, and I recommend using the latest quarterly release. At time of writing, this is known as 'pkgsrc-2009Q2'. Within the next month or so we will release pkgsrc-2009Q3, and you can figure out the names of future releases yourself.

The easiest way to get pkgsrc is using cvs. I keep stuff like this under /content as opposed to the default of /usr, you can use whatever you wish but will need to change all my example scripts to match where you put it.

$ cd /content
$ cvs -d anoncvs@anoncvs.netbsd.org:/cvsroot co -rpkgsrc-2009Q2 -dpkgsrc-2009Q2 -P pkgsrc

Alternatively, you can fetch either bzip2 or gzip archives of the current branch. I recommend the cvs method as, with the branch being updated for security fixes and other important changes, you can easily track it using

$ cd /content/pkgsrc-2009Q2
$ cvs update

pkgsrc configuration

You can download my mk.conf here. This is the primary configuration file for pkgsrc. Again, you may need to tailor this to your environment, and may find it useful to read the pkgsrc guide to understand what it all means.

As I do a lot of pkgsrc development I have a number of virtual machines up and running doing various bits and pieces. Obviously I don't want to copy that mk.conf around, so I also have a small fragment file which is appended to each virtual machine's mk.conf (using bootstrap's --mk-fragment argument) and includes the global copy.

The bulk build setup in pkgsrc requires its own configuration, and for this you will need to edit a file inside pkgsrc. There is an example file provided, so what I usually do is symlink this to the real copy then I can easily keep it up-to-date via cvs. 

$ cd /content/pkgsrc-2009Q2/mk/bulk
$ ln -s build.conf-example build.conf
$ vi build.conf

Again, you can find my personal build.conf here

Finally, there is a configuration file for pkg_chk which is a package inside pkgsrc which makes managing upgrades easier (ideally it should be a part of the main pkgsrc tools but that's for another day). pkgchk.conf is a list of package directories, relative to the pkgsrc top level, which are to be built and installed for this setup. If you have a large installation then pkg_chk has extra features to make it possible to share pkgchk.conf across a number of machines and configure packages on a per-host, per-OS etc basis.

It is highly likely you will want to change the pkgchk.conf file from what I use :-) 

Build scripts 

Once everything is set up, I have two scripts to build then update my packages, intuitively called build-packages and update-packages. These are pretty simple as all the hard work has all been done. build-packages is ran inside the zone, then update-packages on the main host. These scripts hardcode the name of the branch currently used, so you will need to update this when moving to newer releases.

Quick recap

Ok, so here is the stuff I have for my setup and where I keep them.

/content/pkgsrc-2009Q2
Checked out pkgsrc tree, "2009Q2" branch
/content/scripts/create-zone
Creates Solaris zone
/content/scripts/delete-zone
Uninstalls and deletes zone
/content/scripts/build-packages
Bulk build packages inside the zone
/content/scripts/update-packages
Updates installed packages
/install/pkgsrc/misc/mk.conf
Main pkgsrc configuration file
/install/pkgsrc/misc/mk-include.conf
Fragment file included in each zone's mk.conf, sources the global mk.conf
/install/pkgsrc/misc/pkgchk.conf
pkg_chk configuration file
/install/zones/vm-generic.xml
Shared SMF configuration file, symlinked to from e.g. "vm0.xml"


These are the paths where stuff will be created

/install/pkgsrc/distfiles
Source tarballs of packages
/install/pkgsrc/packages/2009Q2
Resulting binary packages
/tmp/pkgsrc
Temporary build area for packages
/content/vwww/www.adsl.perkin.org.uk/pkgstat

Bulk build results directory


It's definitely harder than it should be to get this all setup, but the good news is that once it's done there's very little maintenance.

Kicking it all off

Once everything is setup:

$ /content/scripts/create-zone vm0 
$ ssh vm0 /content/scripts/build-packages
$ /content/scripts/update-packages
$ /content/scripts/delete-zone vm0

This should do the lot. Once build-packages has finished you should, if you configured your email address in build.conf, get an email with the bulk build results which looks similar to this:

http://mail-index.netbsd.org/pkgsrc-bulk/2009/08/23/msg006883.html

A fuller report is available if you configure a web server to serve the 'pkgstat' directory created by the bulk build, and this can help debug problems (again see the above URL for an example).

You will need to add /opt/pkg/sbin:/opt/pkg/bin to $PATH. Configuration files are in /etc/opt/pkg, and log files and metadata are kept in /var/opt/pkg

This stuff should be obsolete

While this all works well for me, it's pretty lame for users who just want to install packages and have stuff work. I'm working on providing regular updates of binary packages, including a SVR4 package of the bootstrap kit, so that in theory all a user needs to do is

$ pkgadd TNFpkgsrc.pkg
$ pkg_add apache22
$ pkg_chk -aurb        # upgrades all installed packages to latest releases

I'm almost there, just needs some tidying up and regular builds. Please feel free to help out!

Tuesday Dec 09, 2008

I recently built a new file server (SuperMicro C2SBX+, Q9550, 8GB, 2*1TB - nice and fast, and has good Solaris support) on which I planned to install Solaris 10 10/08. I'm not a fan of CD/DVD installs, so wanted to jumpstart via PXE, though I only had OSX handy. Here's how I installed my new machine (gromit.adsl.perkin.org.uk/192.168.1.10) from my iMac (192.168.1.30) over the local network.

Step 1, Prepare File System

First off, HFS+ case-insensitive file systems will not work, pkgadd(1M) just cannot grok packages served up like that, so you need to create a UFS image on which to serve your jumpstart environment. Here I create an 8G (plenty for just one install, once I've installed Solaris I'll use that as my jumpstart server) image which I then mount under /install

# hdiutil create -size 8g -type SPARSE -fs UFS -volname "install" install
# hdiutil attach install.sparseimage -mountpoint /install

Next up, download and mount sol-10-u6-ga1-x86-dvd.iso then copy it across to /install.

# rsync -av /Volumes/SOL_10_1008_X86/ /install/sol10u6x/

Step 2, NFS

Share /install via NFS with the correct options. -alldirs allows clients to mount from any point within that file system (which jumpstart requires), and -maproot=root is also required by jumpstart. As this allows root-owned files to be created, make sure you understand the security risks.

# vi /etc/exports
/install        -alldirs -maproot=root
# nfsd checkexports && nfsd enable

Step 3, DHCP

For DHCP I happen to already use my Cisco router as a DHCP server on the local network, so added the following configuration:

ip dhcp pool gromit.adsl.perkin.org.uk
   host 192.168.1.10 255.255.255.0
   hardware-address xxxx.xxxx.xxxx
   bootfile /boot/grub/pxegrub
   next-server 192.168.1.30 
   client-name gromit
   domain-name adsl.perkin.org.uk
   dns-server xxx.xxx.xxx.xxx 
   default-router 192.168.1.1

however, given this is a guide for setting everything up under OSX I also tried using ISC DHCP on OSX to prove it can be done that way too.

I used pkgsrc to install it (I'll add another blog some time showing how to set up pkgsrc)

# cd /usr/pkgsrc/net/isc-dhcpd
# bmake package

And here is my DHCP configuration file in full.

# vi /usr/pkg/etc/dhcp/dhcpd.conf
option domain-name "adsl.perkin.org.uk";
option domain-name-servers xxx.xxx.xxx.xxx;
ddns-update-style none;
authoritative;
log-facility local7;

subnet 192.168.1.0 netmask 255.255.255.0 {
        option routers 192.168.1.1;
}

group {
        filename "/boot/grub/pxegrub";
        next-server 192.168.1.30;

        host gromit {
                hardware ethernet xx:xx:xx:xx:xx:xx;
                fixed-address 192.168.1.10;
                option host-name "gromit.adsl.perkin.org.uk";
        }
}

Finally, start DHCP with:

# /usr/pkg/sbin/dhcpd

Most parts of these configurations should be self-explanatory. The /boot/grub/pxegrub entry is important for our next step, and I'd recommend using that exact pathname for reasons explained later.

Step 4, TFTP

Now, enable the TFTP server which comes with OSX. I added the -s option so tftpd would chroot to the tftpboot directory, both for security reasons and also to ensure that paths specified as /path/to/file would work correctly (relative to /install/tftpboot). I also changed the location of the tftpboot directory so that everything was self-contained within the UFS image. In previous attempts I didn't do this and ran into problems with GRUB which I think are again caused by case-insensitive file systems.

# vi /System/Library/LaunchDaemons/tftp.plist
[...]
        <key>ProgramArguments</key>
        <array>
                <string>/usr/libexec/tftpd</string>
                <string>-i</string>
                <string>-s</string>
                <string>/install/tftpboot</string>
        </array>
[...]
# mkdir /install/tftpboot
# launchctl load -w /System/Library/LaunchDaemons/tftp.plist

You can then create a test file and check that it's working as you expect, using:

# echo "testing" >/install/tftpboot/testfile
# printf "verbose\ntrace\nget testfile\n" | tftp localhost

Step 5, GRUB

Next up, configure PXE booting using GRUB. We need to copy the GRUB images and configuration from the Solaris install DVD then modify it for our environment

# rsync -av /install/sol10u6x/boot/grub /install/tftpboot/boot/
# rsync -av /install/sol10u6x/boot/multiboot /install/sol10u6x/boot/x86.miniroot \
            /install/tftpboot/sol10u6x/

As we are copying the boot files from the DVD, they come hardcoded with particular pathnames to e.g. the menu.lst file. While it may be possible to pass extra parameters to pxegrub and load this from a different path, I simply recommend doing as I do and replicating the /boot/grub/ path structure so that everything Just Works.

The menu.lst file includes kernel arguments and allows you to choose which type of install to perform at startup. My file listed below has 3 choices:

  • Unattended install using a graphical environment (if available). The 'install' keyword after the kernel instructs it to perform an unattended install, so long as it can find the necessary settings from sysidcfg etc.
  • As above, but force the use of the console and do not start a graphical environment (using the 'nowin' keyword)
  • A manual install, so you need to go through the steps of layout out disks, selecting packages, etc.
# vi /install/tftpboot/boot/grub/menu.lst
default=0
timeout=60
title Solaris PXE Unattended Install
        kernel /sol10u6x/multiboot kernel/unix - install -B install_media=192.168.1.30:/install/sol10u6x,sysid_config=192.168.1.30:/install/jumpstart,install_config=192.168.1.30:/install/jumpstart
        module /sol10u6x/x86.miniroot
title Solaris PXE Unattended Install (console)
        kernel /sol10u6x/multiboot kernel/unix - install nowin -B install_media=192.168.1.30:/install/sol10u6x,sysid_config=192.168.1.30:/install/jumpstart,install_config=192.168.1.30:/install/jumpstart
        module /sol10u6x/x86.miniroot
title Solaris PXE Manual Install
        kernel /sol10u6x/multiboot kernel/unix -B install_media=192.168.1.30:/install/sol10u6x
        module /sol10u6x/x86.miniroot

Anyone used to doing jumpstart but with RARP/bootparams will notice the symmetry between install_config etc in the GRUB configuration and similar options in /etc/bootparams. Make sure that the full kernel arguments are all on one line, and that there are no spaces in between the install_media=...,sysid_config=... options.

Step 6, Jumpstart

Finally, set up your Jumpstart configuration. Here's what I personally use, you may want something different

# mkdir /install/jumpstart
# cd /install/jumpstart
# vi sysidcfg
name_service=DNS
{
        domain_name=adsl.perkin.org.uk
        name_server=xxx.xxx.xxx.xxx
}
network_interface=PRIMARY
{
        default_route=192.168.1.1
        netmask=255.255.255.0
        protocol_ipv6=yes
}
nfs4_domain=dynamic
root_password=xxxxxxxx
terminal=xterm
timeserver=localhost
timezone=Europe/London
security_policy=NONE
service_profile=limited_net
system_locale=C

Ordinarily this file is processed using a 'check' script available in the jumpstart_sample directory on the Solaris DVD, however this only works from a Solaris host. To create the rules.ok file, we need to strip out any comments and put entries on one line, then create the checksum (although this isn't actually necessary).

# vi rules # emacs sucks!
hostname gromit.adsl.perkin.org.uk - profile -
# cp rules rules.ok
# echo "# version=2 checksum=$(cksum -o 2 rules | awk '{print $1}')" >> rules.ok

Machine profile. This gives me a full Solaris install (minus OEM stuff) on mirrored ZFS disks with additional dump/swap space (the defaults made dump a bit too small I found).

# vi profile
install_type    initial_install
pool            store auto 4g 4g mirror c1t0d0s0 c1t1d0s0
bootenv         installbe bename s10x_u6wos_07b
cluster         SUNWCall

Step 7, Make A Cup Of Tea

With everything set up you should be able to enable PXE booting in your BIOS and watch it automatically install. One small minor problem you may have if you don't have a BIOS which allows you to hit F12 or similar and choose PXE booting for one boot only is that it will infinitely cycle through installing-rebooting-installing-rebooting... until you change your boot options. If this happens, I recommend making more cups of tea until you happen to return in time to change the BIOS settings. If you aren't able to do this for a while, you may need to add the extra steps 8, 9 and 10 titled "Visit The Bathroom".