Home of the Squeezebox™ & Transporter® network music players.
Results 1 to 3 of 3
  1. #1
    Senior Member gharris999's Avatar
    Join Date
    Apr 2005
    Location
    Santa Fe, NM
    Posts
    3,303

    How to manage running multiple branchs of LMS git code

    This is a proposed wiki how-to. I thought I'd roll it out here first to elicit comments. Anyone please chime in here. If I receive positive feedback, I'll author a wiki page on this topic.

    Goal:

    Using minimal download bandwidth and a minimal on-disc footprint, allow one to run any branch of squeezeboxserver / logitechmediaserver from 7.0 to 7.8 as a service and to easily allow switching between installed branches.

    This is potentially useful to plugin writers who often need to test compatibility with various sbs/lms versions.

    Assumptions:

    • Running on Ubuntu or some debian based distro.
    • Service will run under the user account 'lms'.
    • Local git repository will reside at /usr/share/lms/server.
    • We'll create separate data and log directories for any branch we're going to run.
    • Those data and log dirs will be at /var/lib/lms_data/${BRANCHNAME} and /var/log/lms_log/${BRANCHNAME}
    • Those data and log dirs will be linked to /var/lib/lms and /var/log/lms
    • We'll create a generic 'lms' service for running the code.
    • We'll make updating the repo a service control option.
    • We'll have a script for easily switching between branches.

    So, for example, say we're running the lms 7.8.x git code. Switching to SqueezeCenter 7.3.x would be as easy as:
    Code:
    # /usr/local/sbin/lms-switch-branch.sh 7.3
    Also, for example, updating the currently running branch to the latest code and discarding any local changes would be as easy as:
    Code:
    # service lms force-update
    Preparation:

    Become root
    Code:
    sudo su
    Create the lms user account:
    Code:
    useradd --gid nogroup --no-create-home --no-user-group --system --shell /bin/false "lms"
    Download the latest version of the repo:
    Code:
    git clone -n --depth 1 https://github.com/Logitech/slimserver.git /usr/share/lms/server
    Note: by downloading only the latest revisions for every branch, we keep the downloaded object file to about 250M. Remove the "--depth 1" from that command to make previous revisions available.

    Checkout branch 7.8
    Code:
    cd /usr/share/lms/server
    git checkout 7.8

    Create data and log dirs for the 7.8 branch
    Code:
    mkdir -p /var/lib/lms_data/7.8
    chown -R lms:nogroup /var/lib/lms_data
    mkdir -p /var/log/lms_log/7.8
    chown -R lms:nogroup /var/log/lms_log
    Create links to the data and log dirs..
    Code:
    ln -s /var/lib/lms_data/7.8  /var/lib/lms
    ln -s /var/log/lms_log/7.8 /var/log/lms
    Create a defaults file for the service..
    /etc/default/lms:
    Code:
    SLIMDESC='LMS branch 7.8 git code'
    SLIMUSER='lms'
    SLIMOPTIONS=''
    Create a service control script..
    /etc/init.d/lms:
    Code:
    #!/bin/sh
    
    ### BEGIN INIT INFO
    # Provides:          	lms
    # Required-Start:    	$all
    # Required-Stop:     	$all
    # Should-Start:      	$all
    # Should-Stop:       	$all
    # Default-Start:     	2 3 4 5
    # Default-Stop:      	0 1 6
    # Short-Description:	Startup script for the LMS Media Server git code
    # Description:		LMS Media Server git code powers the Squeezebox, Transporter and SLIMP3 network music
    #				players and is the best software to stream your music to any software MP3
    #				player. It supports MP3, AAC, WMA, FLAC, Ogg Vorbis, WAV and more!
    #				As of version 7.7 it also supports UPnP clients, serving pictures and movies too!
    ### END INIT INFO
    
    
    #
    # $Id$
    #
    # lms initscript for slimserver.pl
    # This file should be placed in /etc/init.d.
    #
    # Original Author: Mattias Holmlund
    # Updated By: Dan Sully, Michael Herger
    #
    # Rewrite 20120515 by Gordon Harris to make conforming with:
    # http://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
    # and based on http://www.thegeekstuff.com/2012/03/lsbinit-script/
    #
    
    # Using the lsb functions to perform the operations.
    . /lib/lsb/init-functions
    
    SLIMSRVC='lms'
    SLIMUSER='lms'
    SLIMGROUP=$(id -ng $SLIMUSER)
    SLIMDESC='LMS Media Server git code'
    REPO=/usr/share/$SLIMSRVC/server
    DAEMON=/usr/share/$SLIMSRVC/server/slimserver.pl
    DAEMON_SAFE=/usr/sbin/${SLIMSRVC}_safe
    PIDFILE=/var/run/${SLIMSRVC}.pid
    SCRIPTNAME=$(basename /etc/init.d/${SLIMSRVC})
    PREFSDIR=/var/lib/${SLIMSRVC}/prefs
    LOGDIR=/var/log/${SLIMSRVC}/
    CACHEDIR=/var/lib/${SLIMSRVC}/cache
    CHARSET=utf8
    SLIMOPTIONS=
    
    # Read config file if it is present.
    if [ -r /etc/default/${SLIMSRVC} ]; then
    	. /etc/default/${SLIMSRVC}
    fi
    
    d_check_running() {
    	if [ -e $PIDFILE ]; then
    		status_of_proc -p $PIDFILE $DAEMON "$SLIMDESC" > /dev/null 2>&1 && status=0 || status=$?
    		if [ $status -eq 0 ]; then
    			log_daemon_msg "$SLIMDESC is already running"
    			log_end_msg 0
    			exit 0
    		fi
    	fi
    }
    
    d_start() {
    	d_check_running
    
    	log_daemon_msg "Starting" "$SLIMDESC"
    
    	# Use lms_safe to restart the daemon when
    	# it dies. This must be done to handle mysql restarts.
    	if start-stop-daemon --start --quiet \
    		--chuid $SLIMUSER \
    		--pidfile $PIDFILE \
    		--exec $DAEMON_SAFE \
    		--background \
    		--make-pidfile \
    		-- \
    		$DAEMON \
    		--prefsdir $PREFSDIR \
    		--logdir $LOGDIR \
    		--cachedir $CACHEDIR \
    		--charset=$CHARSET \
    		$SLIMOPTIONS ; then
    		log_end_msg 0
    	else
    		log_end_msg 1
    	fi
    }
    
    # This starts lms without the safe script..
    d_start_direct() {
    	d_check_running
    
    	log_daemon_msg "Starting" "$SLIMDESC"
    
    	# Make the pid file writeable by lms
    	touch $PIDFILE
    	chown "${SLIMUSER}:${SLIMGROUP}" $PIDFILE
    
    	if start-stop-daemon --start --quiet \
    		--chuid $SLIMUSER \
    		--pidfile $PIDFILE \
    		--exec $DAEMON \
    		--background \
    		--make-pidfile \
    		-- \
    		--pidfile $PIDFILE \
    		--prefsdir $PREFSDIR \
    		--logdir $LOGDIR \
    		--cachedir $CACHEDIR \
    		--charset=$CHARSET \
    		$SLIMOPTIONS ; then
    		log_end_msg 0
    	else
    		log_end_msg 1
    	fi
    }
    
    d_stop() {
    	if [ -e $PIDFILE ]; then
    		status_of_proc -p $PIDFILE $DAEMON "$SLIMDESC" > /dev/null 2>&1 && status=0 || status=$?
    		if [ $status -eq 0 ]; then
    			log_begin_msg "Stoppping $SLIMDESC"
    			start-stop-daemon --oknodo --stop --quiet --pidfile $PIDFILE --retry=TERM/30/KILL/5
    			/bin/rm -rf $PIDFILE
    			log_end_msg 0
    		fi
    	else
    		# status 3: program is not running
    		status=3
    	fi
    
    	if [ $status -gt 0 ]; then
    		# status 1: program is dead and /var/run pid file exists
    		log_daemon_msg "$SLIMDESC is not running"
    	fi
    }
    
    #
    #	Function that sends a SIGHUP to the daemon/service.
    #
    d_reload() {
    	start-stop-daemon --stop --quiet --pidfile $PIDFILE --signal 1
    }
    
    d_status() {
    	if [ -e $PIDFILE ]; then
    		status_of_proc -p $PIDFILE $DAEMON "$SLIMDESC" && exit 0 || exit $?
    	else
    		log_daemon_msg "${SLIMDESC} is not running"
    		cd "$REPO" && in_repo
    		log_daemon_msg "Getting ${SLIMDESC} repository status.."
    		git remote show origin
    		git status
    		log_end_msg 3
    	fi
    }
    
    in_repo(){
    	if [ $(pwd) != "$REPO" ]; then
    		log_daemon_msg "Error: ${REPO} not found."
    		log_end_msg 3
    		exit 128
    	fi
    }
    
    d_update() {
    	log_daemon_msg "Updating $SLIMDESC"
    	cd "$REPO" && in_repo
    	git pull && status=0 || status=$?
    	if [ $status -eq 0 ]; then
    		log_daemon_msg "${SLIMDESC} has ben updated."
    	else
    		log_daemon_msg "Error updating ${SLIMDESC}."
    	fi
    }
    
    d_force_update() {
    	log_daemon_msg "Force-Updating $SLIMDESC"
    	cd "$REPO" && in_repo
    	git reset --hard
    	git clean -fd
    	git pull && status=0 || status=$?
    	if [ $status -eq 0 ]; then
    		log_daemon_msg "${SLIMDESC} has ben updated."
    	else
    		log_daemon_msg "Error updating ${SLIMDESC}."
    	fi
    }
    
    if [ ! -x "$DAEMON" ]; then
    	log_daemon_msg "${DAEMON} not found."
    	log_end_msg 5
    	exit 5
    fi
    
    if [ ! -x "$DAEMON_SAFE" ]; then
    	log_daemon_msg "${DAEMON_SAFE} not found."
    	log_end_msg 5
    	exit 5
    fi
    
    
    case "$1" in
      start)
    	d_start
    	;;
      start-direct)
    	d_start_direct
           ;;
      stop)
    	d_stop
    	;;
    #  reload)
    #	d_reload
    #	;;
      restart|force-reload)
    	d_stop
    	sleep 3
    	d_start
    	;;
      update)
    	d_stop
    	sleep 3
    	d_update
    	sleep 3
    	d_start
           ;;
      force-update)
    	d_stop
    	sleep 3
    	d_force_update
    	sleep 3
    	d_start
           ;;
      status)
           d_status
    	;;
      *)
    	log_action_msg "Usage: $(which service) $(basename $0) {start|stop|restart|force-reload|update|force-update|status}"
    	exit 2
    	;;
    esac
    
    exit $?
    Create a service safe script..
    /usr/sbin/lms_safe:
    Code:
    #!/bin/bash
    
    # $Id$
    
    if [ $# = 0 ]
    then
      echo "To stop Logitech Media Server git code, kill this script instead of the"
      echo "actual lms process."
      echo
      echo "Usage: $0 lms-binary lms-arguments"
      exit 1
    fi
    
    function clean_up {
      # Kill the daemon if it is running
      kill $SLIMPID
      echo $(date "+%F %H:%M:%S") $(basename $0) "stopped." >> /var/log/lms/server.log
      exit
    }
    
    trap clean_up SIGINT SIGHUP SIGTERM
    
    echo $(date "+%F %H:%M:%S") $(basename $0) "started." >> /var/log/lms/server.log
    
    
    while true
    do
      # From the Bash Reference Manual:
      # When Bash receives a signal for which a trap has been set 
      # while waiting for a command to complete, the trap will not 
      # be executed until the command completes. When Bash is waiting
      # for an asynchronous command via the wait builtin, the reception
      # of a signal for which a trap has been set will cause the wait
      # builtin to return immediately with an exit status greater than
      # 128, immediately after which the trap is executed.
    
      "$@" --norestart > /dev/null 2>&1 &
      SLIMPID=$!
      
      # wait for the server to get started before wait()
      sleep 5
      
      wait $SLIMPID
      echo $(date "+%F %H:%M:%S") "Logitech Media Server git code died. Restarting." >> /var/log/lms/server.log
    
      # Normally, when the server realizes that the mysql-connection is gone,
      # the mysql server has already been started again. So no need to sleep
      # here.
    
    done
    ..to be continued..
    Last edited by gharris999; 2012-05-17 at 12:08.

  2. #2
    Senior Member gharris999's Avatar
    Join Date
    Apr 2005
    Location
    Santa Fe, NM
    Posts
    3,303
    ..continued.


    Create a log rotate script..
    /etc/logrotate.d/lms:
    Code:
    /var/log/lms/server.log {
      weekly
      rotate 5
      size 200k
      compress
      missingok
    
      postrotate
        # send USR1 to squeezebox PID to reset logging
        /bin/kill -USR1 `pgrep -f 'perl.*slimserver.pl' -n 2>/dev/null` 2>/dev/null || :
      endscript
    }
    
    /var/log/lms/scanner.log {
      weekly
      rotate 5
      size 200k
      compress
      missingok
    }
    Create service control links:
    Code:
    update-rc.d -f lms remove >/dev/null 2>&1
    update-rc.d -f lms defaults
    Create a branch switching script:
    /usr/local/sbin/lms-switch-branch.sh
    Code:
    #!/bin/sh
    
    NEWBRANCH='7.8'
    ISGOODBRANCH=0
    #Discard local changes...
    DISCARD=0
    #Update repo
    UPDATE=0
    
    if [ ! -z "$1" ]; then
      NEWBRANCH="$1"
    fi
    
    # Change to the repo dir..
    cd /usr/share/lms/server
    
    # Get a list of the available branches..
    BRANCHES=`git branch -r | sed -n -e 's#^.*origin/\(.*\)$#\1#p'`
    
    for BRANCH in $BRANCHES
    do
      if [ "$NEWBRANCH" = "$BRANCH" ]; then
        ISGOODBRANCH=1
      fi
    done
    
    if [ $ISGOODBRANCH -lt 1 ]; then
      echo "Error: ${NEWBRANCH} is not a branch of github.com/Logitech/slimserver.git"
      echo "Available branches:"
      echo $BRANCHES
      exit 1
    fi
    
    # Stop the service..
    service lms stop
    
    # Do a hard reset of the repo to discard any local changes..
    if [ $DISCARD -gt 0 ]; then
        git reset --hard
        git clean -fd
    fi
    
    # Switch to the new branch
    git checkout "$NEWBRANCH"
    
    if [ $? -gt 0 ]; then
      echo "Error checking out branch ${NEWBRANCH}."
      exit 1
    fi
    
    # Update the default file with the name of the new branch
    RE="s/^SLIMDESC=.*$/SLIMDESC='LMS branch ${NEWBRANCH} git code'"
    sed -i -e "$RE" /etc/default/lms
    
    # Update the repo
    if [ $UPDATE -gt 0 ]; then
      git pull
    fi
    
    # Create new data & log dirs..
    LIBDIR="/var/lib/lms_data/${NEWBRANCH}"
    LOGDIR="/var/log/lms_log/${NEWBRANCH}"
    
    if [ ! -d "$LIBDIR" ]; then
      mkdir -p "$LIBDIR"
    fi
    
    if [ ! -d "$LOGDIR" ]; then
      mkdir -p "$LOGDIR"
    fi
    
    # Fix permissions
    chown -r lms:nogroup "$LIBDIR"
    chown -r lms:nogroup "$LOGDIR"
    
    # Create new data & log links
    LIBDIRLINK='/var/lib/lms'
    LOGDIRLINK='/var/log/lms'
    
    
    if [ -L "$LIBDIRLINK" ]; then
      rm "$LIBDIRLINK"
    fi
    
    if [ ! -d "$LIBDIRLINK" ]; then
      ln -s "$LIBDIR" "$LIBDIRLINK" 
    fi
    
    if [ -L "$LOGDIRLINK" ]; then
      rm "$LOGDIRLINK"
    fi
    
    if [ ! -d "$LOGDIRLINK" ]; then
      ln -s "$LOGDIR" "$LOGDIRLINK" 
    fi
    
    # Restart the service..
    service lms start
    exit $?
    Script for running the git code from the console in debug mode:
    lms-git-debug.sh
    Code:
    #!/bin/bash
    # Script to debug running of lms git code..
    
    #RUNASROOT=1
    RUNASROOT=0
    
    INSTNAME='lms'
    INSTUSER='lms'
    
    PIDFILE=/var/lib/${INSTNAME}/${INSTNAME}.pid
    PREFSDIR=/var/lib/${INSTNAME}/prefs
    LOGDIR=/var/log/${INSTNAME}
    CACHEDIR=/var/lib/${INSTNAME}/cache
    PUSER=${INSTUSER}
    PGROUP=`id -ng $PUSER`
    OUTFILE=./${INSTNAME}-git-debug.txt
    
    if [ -e ${PIDFILE} ]; then
      rm ${PIDFILE}
    fi
    
    echo "Attempting to start ${INSTNAME}.."
    echo "  Console output redirected to ${OUTFILE}.."
    echo "  Hit CTRL+C to terminate.."
    
    if [[ $RUNASROOT -eq 1 ]]; then
      /usr/bin/perl /usr/share/${INSTNAME}/server/slimserver.pl --pidfile=${PIDFILE} --user=${PUSER} --group=${PGROUP} --cachedir=${CACHEDIR} --prefsdir=${PREFSDIR} --logdir=${LOGDIR} --charset=utf8 --diag --d_startup >${OUTFILE} 2>&1
    else
      sudo -u ${INSTUSER} /usr/bin/perl /usr/share/${INSTNAME}/server/slimserver.pl --pidfile=${PIDFILE} --cachedir=${CACHEDIR} --prefsdir=${PREFSDIR} --logdir=${LOGDIR} --charset=utf8 --diag --d_startup >${OUTFILE} 2>&1
    fi
    
    rm ${PIDFILE}
    
    echo "Done!  Examine ${OUTFILE} for details.."
    That's it for now. Mostly, I'm looking for comments here on the advisability of this approach.

  3. #3
    Senior Member gharris999's Avatar
    Join Date
    Apr 2005
    Location
    Santa Fe, NM
    Posts
    3,303
    Ok, I've put together an install script that automates all the above steps, installing a 'lms' service which runs the logitechmediaserver git code. I've tested this script with Ubuntu 12.04 and Fedora 16. On Ubuntu (and other debian systems) the script installs a regular sysv-style init script. On Fedora and other distros using systemd, the script installs unit files.
    Attached Files Attached Files

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •