Building An RPM

Posted on: 2016-09-11

Every once in a while somebody asks me to build an RPM. This unfortunately doesn't happen often enough that I can remember the process and I have to do a bunch of digging. When I do that digging most of what I find is how to create RPMs from your typical GNU ./configure && make .tar.gz source bundles and not from just a bunch of files, which is what I usually need. This post will show you and future me how to throw some random files into an RPM the same way you would a .tar or a .zip.

Install some software:

yum install rpmdevtools

Create an account to build the rpm with and become that user:

useradd rpmbuild
su - rpmbuild

Create the dirs and spec


vim rpmbuild/SPECS/myapp.spec

#jut dumb files. don't compile my python
%global __os_install_post /bin/true
Name: myapp
Version: 2016091100
Release:        1%{?dist}
Summary: my app is some bash scripts needed on our servers

License: GPL
BuildArch: noarch

collection of scripts to help sysadmins and developers troubleshoot things

#%setup -q

#make %{?_smp_mflags}

#make install DESTDIR=%{buildroot}
rm -Rf %{_topdir}/RPMS/*
rm -Rf %{_topdir}/SRPMS/*
#just copy files from sources. no reason to tar in between.
cp -Rf %{_topdir}/SOURCES/* $RPM_BUILD_ROOT

%attr(0755,root,root) /usr/sbin/*



#%{_bindir}/systemctl daemon-reload
#%{_bindir}/systemctl enable runlast.timer

#%{_bindir}/systemctl disable runlast.timer
#%{_bindir}/systemctl daemon-reload

*Sun Sep 11 2016 dminnich@localhost
- first release

Some quick notes:

  • Specs or build recipes if you will go into SPECS

  • SOURCES typically holds ./configure && make style .tar.gz. %prep in the spec looks at Source0 and extracts it to BUILD. We won't be using this functionality so its commented out. We will however be placing files in SOURCES, but any folder would work.

  • %build in the spec does the ./configure && make style actions inside of BUILD. We won't be using this so its commented out.

  • %install typically does the make install and copies files from BUILD to BUILDROOT. We are cheating here and just copying files we want over wholesale. We are also removing old build files and previous RPMs and SRPMs. On shared systems you shouldn't really purge RPMs like this, but I do it while I do dev work so I can keep building the same production next version of the RPM.

  • %files sets the permissions the files in the RPMs and files on the end user systems will have. You must have a line or pattern for all the files you add.

  • %doc would contain man pages and similar if you have any.

  • %clean cleans up and prepares for the next build. We simply blow away the directory that had the files in it.

  • %post and %postun are scripts you can run after an install and after an uninstall. We aren't using any here but I left them as examples. This stuff gets tricky fast with upgrades and other things see this if necessary.

  • %changelog should contain changes to the RPM and entries have to be the the specific date email format.

  • Be sure to increment the Version in the spec before each production build.

  • The %global line tells the rpmbuilder not to do anything 'smart' while building the RPM. It for instance won't compile python scripts, strip symbols and do other things. This should be fine if you are building local sysadmin packages and not real world packages that the masses will consume.

  • Fedora Wiki is a great reference for additional information.

Placing your files:

Put the files you want to land on the end systems in their exact location underneath SOURCES. For instance, we will be landing /usr/sbin/ so we will be creating SOURCES/usr/bin/

cd rpmbuild/SOURCES
mkdir -p usr/sbin
echo "echo "HI"" >> usr/sbin/

Build and inspect your RPM:

cd ~/rpmbuild/
rpmbuild -ba SPECS/myapp.spec

rpm -qpi RPMS/noarch/myapp-2016091100-1.el7.centos.noarch.rpm 
Name        : myapp
Version     : 2016091100
Release     : 1.el7.centos
Architecture: noarch
Install Date: (not installed)
Group       : Unspecified
Size        : 8
License     : GPL
Signature   : (none)
Source RPM  : myapp-2016091100-1.el7.centos.src.rpm
Build Date  : Sun 11 Sep 2016 02:13:50 PM UTC
Build Host  : a
Relocations : (not relocatable)
Summary     : my app is some bash scripts needed on our servers
Description :
collection of scripts to help sysadmins and developers troubleshoot things

rpm -qpl RPMS/noarch/myapp-2016091100-1.el7.centos.noarch.rpm 

Install the RPM and try it out:

exit #become root
yum localinstall /home/rpmbuild/rpmbuild/RPMS/noarch/myapp-2016091100-1.el7.centos.noarch.rpm

Bonus...Publish it in a yum repo:

#as root
yum -y install httpd createrepo
mkdir /var/www/html/repo
cp /home/rpmbuild/rpmbuild/RPMS/noarch/myapp-2016091100-1.el7.centos.noarch.rpm /var/www/html/repo/
createrepo /var/www/html/repo/
systemctl enable httpd
systemctl start httpd

Updating your RPM:

su - rpmbuild
vim rpmbuild/SOURCES/usr/sbin/  #make changes
increment the Version in the spec
rpmbuild -ba SPECS/myapp.spec
exit #become root.  only do these next steps if you stood up a repo as well
/bin/cp -f /home/rpmbuild/rpmbuild/RPMS/noarch/*rpm /var/www/html/repo/
createrepo /var/www/html/repo/

Consuming it on clients:

vim /etc/yum.repos.d/myrepo.repo
baseurl=  #your IP

yum install myapp

Orange Pi Audio Receiver

Posted on: 2016-08-28

I like to buy gadgets from china off sites like gearbest and aliexpress. Every once in a while you run across a really awesome device that you would never find in the states. Also, things are super duper cheap so if what you bought ends up sucking you didn't loose much. I recently bought a few Orange Pi development boards and so far I'm enjoying them. Some of these models are a bit cheaper and more powerful than their comparable Raspberry Pi boards. The community is smaller though and Allwinner isn't great to the opensource community but the community is trying really hard to get most of their SOCs fully into the mainline linux kernel, which would be really awesome.

Anyhow, my first project with one of them was to create an audio receiver because my sound bar is just too far away from my couch to allow bluetooth to work well. Here is what I did...


At the end of this your Orange Pi PC will

1) Accept Pulseaduio streams, which will allow you to send it all or specific application audio from linux boxes easily.

2) Accept bluetooth audio connections to mirror all sounds from devices like phones

3) Accept DLNA sound streams from computers and phones.

Pre setup

Buy the Orange Pi PC, an 8GB sdcard and a cheap bluetooth USB adapter and a 3.5" audio cable. Load up Jessie Desktop (desktop is needed because pulseaudio in "system" mode is hacky) on the SD card, hook the audio cable up to some speakers, turn the speakers up and power on the device. On first boot, change the root password, create a user account, etc.
Then do your typical updates with apt update, apt upgrade, reboot.

Run all commands on the Pi as the user you created unless otherwise noted.

Networking Notes: DLNA SSDP and Pulseaudio in mDNS mode are both natively limited to a single layer 2 network / multicast domain. If you are on a standard home network and don't know what the above means, you are likely fine.

However, if you have an advanced network (different subnets, VLANs, etc), you will need to setup an avahi reflector for Pulseaudio and a IGMP Proxy + firewall rules for DLNA. Or do some trunking and multiple interfaces on your main server.

Pulseaudio Network Sharing

On the Pi

sudo apt-get install pulseaudio pulseaudio-module-zeroconf avahi-daemon dbus-x11

sudo vim /etc/pulse/  #add the following to the bottom. update the IP range if necessary.
load-module module-native-protocol-tcp auth-ip-acl=;
load-module module-zeroconf-publish

sudo reboot

alsamixer #F6 through all sound cards and make sure levels are up
#audo lineout on audiocodec needs to be unmuted

On the client linux machine

sudo apt-get install paprefs pavucontrol avahi-daemon
Check "Make discoverable PulseAudio network sound device avaliable locally"
pulseaduio -k
pavucontrol  > Output devices > look for something like "audiocodec on user@orangepiFQDN"

Play something to that to make sure it works

If the client can't see the Pi, it may be do to avahi/mDNS being a pain. You can try putting something like the following into /etc/pulse/ on the client and restarting pulseaudio (pulseaudio -k). Update the IP to be the IP of your Pi. load-module module-tunnel-sink server= sink_name=opi channels=2 rate=44100

Bluetooth reciever

On the Pi

sudo apt-get install pulseaudio-module-bluetooth bluez-tools
sudo gpasswd -a username pulse
sudo gpasswd -a username lp
sudo gpasswd -a username audio
sudo gpasswd -a pulse lp
sudo gpasswd -a pulse audio
sudo sh -c "echo 'extra-arguments = --exit-idle-time=-1 --log-target=syslog' >> /etc/pulse/client.conf"
sudo hciconfig hci0 up
sudo hciconfig hci0 class 0x200420
sudo reboot

sudo bluetoothctl
agent on
discoverable on
scan on
pair MAC
connect MAC
..enter codes..
trust MAC
info MAC #you should see Connected: yes

Play a song on your phone and see if it works.

This setup was kind of finicky for me. I had to mess around in bluetoothctl for quite a while to get the devices to pair. Once they paired though I can connect with one click and no pin.

DLNA reciever

On the Pi

sudo apt-get install rygel rygel-gst-launch rygel-tracker rygel-playbin rygel-preferences wavpack paprefs pavucontrol screen gstreamer-tools gstreamer0.10-alsa gstreamer0.10-fluendo-mp3 gstreamer0.10-gconf gstreamer0.10-plugins-bad gstreamer0.10-plugins-base gstreamer0.10-plugins-base-apps gstreamer0.10-plugins-good gstreamer0.10-plugins-ugly gstreamer0.10-pulseaudio gstreamer0.10-tools gstreamer1.0-alsa gstreamer1.0-fluendo-mp3 gstreamer1.0-plugins-bad gstreamer1.0-plugins-base gstreamer1.0-plugins-base-apps gstreamer1.0-plugins-good gstreamer1.0-plugins-ugly gstreamer1.0-pulseaudio gstreamer1.0-tools
paprefs > Network > Check both DLNA related boxes
sudo reboot
ctrl-a d

Cast a song from your phone and see if it works.

If you have problems you can start rygle like so G_MESSAGES_DEBUG=all rygel -g 5 to get more info. You may also want to try different file types (ie: ogg, speex) to make sure you don't have a proprietary codec problem.


git Backed Static Content Web Hosting PaaS

Posted on: 2015-05-24

I've been playing with OpenShift and another PaaS vendor lately. The fact that you can do a git push and everything else is handled automatically for you is really neat. I wanted to learn more about how this all worked, so I decided to try to create my own PaaS-like setup. Since this was to be a learning experience and not a for profit product, I decided to target a simple use case of ~username static content hosting. I also figured this would be a good starting place for extension by others and I could use it to replace my current hosting service one day.

The first thing I learned with this project is that you need a git post-receive hook to checkout the users repo and then build and deploy the results. So for me that was a simple git checkout and rm -Rf ~/public_html followed finally by a cp -Rf repo/public_html ~/public_html.

Next up, since I wanted to share this project and allow others to offer the same service and potentially build a network a la I decided the server build process and other orchestration parts needed to be uniform and easy to use. Since where I work is a puppet shop, I decided to learn and use some Ansible for these pieces.

Now that the git hook, server build and backend account creation stuff was done, all I needed was a web frontend where people could sign-up for accounts. A buddy of mine had been talking about sinatra and I've been meaning to learn some more Ruby, so I created the front end using those technologies.

All and all this was a fun project and I'm very pleased with the results. If you happen to need a PaaS static content host or want a PaaS like system to extend for you own needs be sure to check out my work at

<<Newer Older>>