Added prep.sh script for automated builds

* Changed README.md commensurately
* Add cameras.sql to .gitignore to not commit personal camera data
* Change CMakeLists.txt to explicitly refer to hand-built libevent dirs
This commit is contained in:
Dolf Starreveld 2016-02-07 22:59:29 -08:00
parent 3b0dc5368e
commit e7456643cd
4 changed files with 340 additions and 25 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
build
debug
obj-*
cameras.sql
debian/files
debian/moonfire-nvr.debhelper.log
debian/moonfire-nvr.postinst.debhelper

106
README.md
View File

@ -47,7 +47,7 @@ make this possible:
See the [github page](https://github.com/scottlamb/moonfire-nvr) (in case
you're not reading this text there already). You can download the bleeding
edge version from the commandline via git:
edge version from the command line via git:
$ git clone https://github.com/scottlamb/moonfire-nvr.git
@ -69,7 +69,7 @@ from source. It requires several packages to build:
[nghttp2](https://github.com/tatsuhiro-t/nghttp2) in the future.)
Unfortunately, the libevent 2.0 bundled with current Debian releases is
unsuitable.
* [gflags](http://gflags.github.io/gflags/), for commandline flag parsing.
* [gflags](http://gflags.github.io/gflags/), for command line flag parsing.
* [glog](https://github.com/google/glog), for debug logging.
* [gperftools](https://github.com/gperftools/gperftools), for debugging.
* [googletest](https://github.com/google/googletest), for automated testing.
@ -92,14 +92,50 @@ pre-requisites (see also the `Build-Depends` field in `debian/control`):
libgoogle-glog-dev \
libgoogle-perftools-dev \
libre2-dev \
sqlite3 \
libsqlite3-dev \
pkgconf \
uuid-runtime \
uuid-dev
libevent 2.1 will have to be installed from source. In the future, this
dependency may be replaced or support may be added for automatically building
libevent in-tree to avoid the inconvenience.
uuid-runtime is only necessary if you wish to use the uuid command to generate
uuids for your cameras (see below). If you obtain them elsewhere, you can skip this
package.
You can continue to follow the build/install instructions below for a manual
build and install, or alternatively you can run the prep script called `prep.sh`.
$ cd moonfire-nvr
$ ./prep.sh
The script will take the following command line options, should you need them:
* `-E`: Forcibly purge all existing libevent packages. You would only do this
if there is some apparent conflict (see remarks about building libevent
from source).
* `-f`: Force a build even if the binary appears to be installed. This can be useful
on repeat builds.
* `-S`: Skip updating and installing dependencies through apt-get. This too can be
useful on repeated builds.
You can edit variables at the start of the script to influence names and
directories, but defaults should suffice in most cases. For details refer to
the script itself. We will mention just one option, needed when you follow the
suggestion to separate database and samples between flash storage and a hard disk.
If you have the hard disk mounted on, lets say `/media/nvr`, and you want to
store the video samples inside a directory named `samples` there, you would set:
SAMPLES_DIR=/media/nvr/samples
The script will perform all necessary steps to leave you with a fully built,
installed moonfire-nvr binary and (running) system service. The only thing
you'll have to do manually is add your camera configuration(s) to the database.
For instructions, you can skip to "[Camera configuration and hard disk mounting](#camera)".
Once prerequisites are installed, Moonfire NVR can be built as follows:
$ mkdir build
@ -114,23 +150,43 @@ installed, you may be able to prepare a `.deb` package:
$ sudo apt-get install devscripts dh-systemd
$ debuild -us -uc
# Installation
# Further configuration
Moonfire NVR should be run under a dedicated user. It keeps two kinds of
state:
* a SQLite3 database, typically <1 GiB. It should be stored on flash if
* a SQLite database, typically <1 GiB. It should be stored on flash if
available.
* the "sample file directory", which holds the actual samples/frames of H.264
video. This should be quite large and typically is stored on a hard drive.
Both are intended to be accessed only by Moonfire NVR itself. However, the
interface for adding new cameras is not yet written, so you will have to
manually create the database and insert cameras with the `sqlite3` commandline
manually create the database and insert cameras with the `sqlite3` command line
tool prior to starting Moonfire NVR.
Manual commands would look something like this:
$ sudo addgroup --system moonfire-nvr
$ sudo adduser --system moonfire-nvr --home /var/lib/moonfire-nvr
$ sudo mkdir /var/lib/moonfire-nvr
$ sudo -u moonfire-nvr -H mkdir db sample
$ sudo -u moonfire-nvr sqlite3 ~moonfire-nvr/db/db < path/to/schema.sql
## <a name="cameras"></a>Camera configuration and hard drive mounting
If a dedicated hard drive is available, set up the mount point:
$ sudo vim /etc/fstab
$ sudo mount /var/lib/moonfire-nvr/sample
Once setup is complete, it is time to add camera configurations to the
database. However, the interface for adding new cameras is not yet written,
so you will have to manually insert cameras configurations with the `sqlite3`
command line tool prior to starting Moonfire NVR.
Before setting up a camera, it may be helpful to test settings with the
`ffmpeg` commandline tool:
`ffmpeg` command line tool:
$ ffmpeg \
-i "rtsp://admin:12345@192.168.1.101:554/Streaming/Channels/1" \
@ -140,16 +196,21 @@ Before setting up a camera, it may be helpful to test settings with the
-flags:v +global_header \
test.mp4
Once you have a working `ffmpeg` commandline, set up Moonfire NVR as follows:
Once you have a working `ffmpeg` command line, insert the camera config as
follows. See the schema SQL file's comments for more information.
Note that the sum of `retain_bytes` for all cameras combined should be
somewhat less than the available bytes on the sample file directory's
filesystem, as the currently-writing sample files are not included in
this sum. Be sure also to subtract out the filesystem's reserve for root
(typically 5%).
In the following example, we generate a uuid which is then later used
to uniquely identify this camera. Thus, you will generate a new one for
each camera you insert using this method.
$ sudo addgroup --system moonfire-nvr
$ sudo adduser --system moonfire-nvr --home /var/lib/moonfire-nvr
$ sudo mkdir /var/lib/moonfire-nvr
$ sudo -u moonfire-nvr -H mkdir db sample
$ uuidgen | sed -e 's/-//g'
b47f48706d91414591cd6c931bf836b4
$ sudo -u moonfire-nvr sqlite3 db/db
sqlite3> .read path/to/schema.sql
$ sudo -u moonfire-nvr sqlite3 ~moonfire-nvr/db/db
sqlite3> insert into camera (
...> uuid, short_name, description, host, username, password,
...> main_rtsp_path, sub_rtsp_path, retain_bytes) values (
@ -159,18 +220,10 @@ Once you have a working `ffmpeg` commandline, set up Moonfire NVR as follows:
...> '/Streaming/Channels/2', 104857600);
sqlite3> ^D
See the schema SQL file's comments for more information. Note that the sum of
`retain_bytes` for all cameras should be somewhat less than the available
bytes on the sample file directory's filesystem, as the currently-writing
sample files are not included in this sum. Be sure also to subtract out the
filesystem's reserve for root (typically 5%).
## System Service
If a dedicated hard drive is available, set up the mount point:
$ sudo vim /etc/fstab
$ sudo mount /var/lib/moonfire-nvr/sample
Moonfire NVR can be run as a systemd service. Create
Moonfire NVR can be run as a systemd service. If you used `prep.sh` this has
been done for you. If not, Create
`/etc/systemd/system/moonfire-nvr.service`:
[Unit]
@ -208,7 +261,12 @@ documentation for more information. The [manual
pages](http://www.freedesktop.org/software/systemd/man/) for `systemd.service`
and `systemctl` may be of particular interest.
# Troubleshooting
While Moonfire NVR is running, logs will be written to `/tmp/moonfire-nvr.INFO`.
Also available will be `/tmp/moonfire-nvr.WARNING` and `/tmp/moonfire-nvr.ERROR`.
These latter to contain only warning or more serious messages, respectively only
error messages.
# <a name="help"></a> Getting help and getting involved

254
prep.sh Executable file
View File

@ -0,0 +1,254 @@
#!/bin/bash
#
# This file is part of Moonfire NVR, a security camera network video recorder.
# Copyright (C) 2016 Scott Lamb <slamb@slamb.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the
# OpenSSL library under certain conditions as described in each
# individual source file, and distribute linked combinations including
# the two.
#
# You must obey the GNU General Public License in all respects for all
# of the code used other than OpenSSL. If you modify file(s) with this
# exception, you may extend this exception to your version of the
# file(s), but you are not obligated to do so. If you do not wish to do
# so, delete this exception statement from your version. If you delete
# this exception statement from all source files in the program, then
# also delete it here.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# Script to prepare for moonfire-nvr operations
#
# Command line options:
# -f: Force clean build, even if binary already installed
# -S: Skip apt-get update and install
#
# Configuration variables. Should only need minimal, or zero, changes.
# Empty values will use defaults.
#
# User and group
# Default: or whatever is in $NVR_USER (default "moonfire-nvr")
#
NVR_USER=
NVR_GROUP=
# Port for web server
# Default: 8080
#
NVR_PORT=
# This should, ideally, be a location on flash storage under which the
# moonfire user's home directory will be created.
# Default: "/var/lib"
#
NVR_HOME_BASE=
# Set to mountpoint of media directory, empty to stay in home directory
# Default: empty
SAMPLES_DIR=
# Set to path for media directory relative to mountpoint
# Default: "samples"
#
SAMPLES_DIR_NAME=
# Binary location
# Default: "/usr/local/bin/moonfire-nvr"
#
SERVICE_BIN=
# Service name
# Default: "moonfire-nvr"
#
SERVICE_NAME=
# Service Description
# Default: "Moonfire NVR"
#
SERVICE_DESC=
# --------------------------------------------------------------------
# Derived variables: Do not modify!
#
# Determine directory path of this script
#
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until file no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
# if $SOURCE was relative symlink, resolve relative to path of symlink
[[ "$SOURCE" != /* ]] && SOURCE="$DIR/$SOURCE"
done
SRC_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"/src
NVR_USER="${NVR_USER:-moonfire-nvr}"
NVR_GROUP="${NVR_GROUP:-$NVR_USER}"
NVR_PORT="${NVR_PORT:-8080}"
NVR_HOME_BASE="${NVR_HOME_BASE:-/var/lib}"
NVR_HOME="${NVR_HOME_BASE}/${NVR_USER}"
DB_NAME="${DB_NAME:-db}"
DB_DIR="${DB_DIR:-$NVR_HOME/db}"
SAMPLES_DIR_NAME="${SAMPLES_DIR_NAME:-samples}"
SAMPLES_DIR="${SAMPLES_DIR:-$NVR_HOME/$SAMPLES_DIR_NAME}"
SERVICE_NAME="${SERVICE_NAME:-moonfire-nvr}"
SERVICE_DESC="${SERVICE_DESC:-Moonfire NVR}"
SERVICE_BIN="${SERVICE_BIN:-/usr/local/bin/moonfire-nvr}"
# Process command line options
#
while getopts ":DEfS" opt; do
case $opt in
D) SKIP_DB=1
;;
E) PURGE_LIBEVENT=1
;;
f) FORCE_BUILD=1
;;
S) SKIP_APT=1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
exit 1
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 1
;;
esac
done
# Setup all packages we need
#
echo 'Preparing and downloading packages we need...'; echo
if [ "${SKIP_APT:-0}" != 1 ]; then
sudo apt-get update
[ "${PURGE_LIBEVENT:-0}" == 1] && sudo apt-get --purge remove libevent-*
sudo apt-get install \
build-essential \
cmake \
libavcodec-dev \
libavformat-dev \
libavutil-dev \
libgflags-dev \
libgoogle-glog-dev \
libgoogle-perftools-dev \
libre2-dev \
sqlite3 \
libsqlite3-dev \
pkgconf \
uuid-runtime \
uuid-dev
fi
# Check if binary is installed. Setup for build if it is not
#
if [ ! -x "${SERVICE_BIN}" ]; then
echo "Binary not installed, building..."; echo
FORCE_BUILD=1
fi
# Build if requested
#
if [ "${FORCE_BUILD:-0}" -eq 1 ]; then
# Remove previous build, if any
[ -d build ] && rm -fr build 2>/dev/null
mkdir build; cd build
cmake .. && make && sudo make install
if [ -x "${SERVICE_BIN}" ]; then
echo "Binary installed..."; echo
else
echo "Build failed to install..."; echo
exit 1
fi
fi
# Create user and groups
#
echo 'Create user/group and directories we need...'; echo
sudo addgroup --quiet --system ${NVR_GROUP}
sudo adduser --quiet --system ${NVR_USER} --home "${NVR_HOME}"
if [ ! -d "${NVR_HOME}" ]; then
sudo mkdir "${NVR_HOME}"
fi
sudo chown ${NVR_USER}:${NVR_GROUP} "${NVR_HOME}"
# Prepare samples directory
#
if [ -z "${SAMPLES_DIR}" ]; then
SAMPLES_PATH="${NVR_HOME}/${SAMPLES_DIR_NAME}"
if [ ! -d "${SAMPLES_PATH}" ]; then
sudo -u ${NVR_USER} -H mkdir "${SAMPLES_PATH}"
fi
else
SAMPLES_PATH="${SAMPLES_DIR}"
if [ ! -d "${SAMPLES_PATH}" ]; then
sudo mkdir "${SAMPLES_PATH}"
echo ">>> Do not forget to edit /etc/fstab to mount samples media"; echo
fi
fi
# Prepare for sqlite directory and set schema into db
#
echo 'Create database...'; echo
if [ ! -d "${DB_DIR}" ]; then
sudo -u ${NVR_USER} -H mkdir "${DB_DIR}"
fi
DB_PATH="${DB_DIR}/${DB_NAME}"
CAMERAS_PATH="${SRC_DIR}/../cameras.sql"
[ "${SKIP_DB:-0}" == 0 ] && sudo -u ${NVR_USER} -H sqlite3 "${DB_PATH}" < "${SRC_DIR}/schema.sql"
if [ -r "${CAMERAS_PATH}" ]; then
echo 'Add cameras...'; echo
sudo -u ${NVR_USER} -H sqlite3 "${DB_PATH}" < "${CAMERAS_PATH}"
fi
# Prepare service files
#
SERVICE_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
sudo sh -c "cat > ${SERVICE_PATH}" <<NVR_EOF
[Unit]
Description=${SERVICE_DESC}
After=network-online.target
[Service]
ExecStart=${SERVICE_BIN} \\
--sample_file_dir=${SAMPLES_PATH} \\
--db_dir=${DB_DIR} \\
--http_port=${NVR_PORT}
Type=simple
User=${NVR_USER}
Nice=-20
Restart=on-abnormal
CPUAccounting=true
MemoryAccounting=true
BlockIOAccounting=true
[Install]
WantedBy=multi-user.target
NVR_EOF
# Configure and start service
#
if [ -f "${SERVICE_PATH}" ]; then
echo 'Configuring system daemon...'; echo
sudo systemctl daemon-reload
sudo systemctl restart ${SERVICE_NAME}
echo 'Getting system daemon status...'; echo
sudo systemctl status ${SERVICE_NAME}
fi

View File

@ -59,6 +59,8 @@ set(MOONFIRE_NVR_SRCS
uuid.cc
web.cc)
link_directories(${LIBEVENT_LIBRARY_DIRS})
add_library(moonfire-nvr-lib ${MOONFIRE_NVR_SRCS} ${PROTO_SRCS} ${PROTO_HDRS})
target_link_libraries(moonfire-nvr-lib ${MOONFIRE_DEPS})
@ -84,7 +86,7 @@ set(MOONFIRE_NVR_TESTS
foreach(test ${MOONFIRE_NVR_TESTS})
add_executable(${test}-test ${test}-test.cc testutil.cc)
target_link_libraries(${test}-test GTest GMock moonfire-nvr-lib)
target_link_libraries(${test}-test GTest GMock moonfire-nvr-lib )
add_test(NAME ${test}-test
COMMAND ${test}-test
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})