aboutsummaryrefslogtreecommitdiff
path: root/extra
diff options
context:
space:
mode:
Diffstat (limited to 'extra')
-rw-r--r--extra/Makefile128
-rw-r--r--extra/fuss-el7.patch28
-rw-r--r--extra/fuss.conf.apache60
-rwxr-xr-xextra/fuss.init172
-rw-r--r--extra/fuss.service20
-rw-r--r--extra/fuss.spec167
-rw-r--r--extra/fuss.sysusers3
-rw-r--r--extra/pip-helper.sh32
8 files changed, 610 insertions, 0 deletions
diff --git a/extra/Makefile b/extra/Makefile
new file mode 100644
index 0000000..d18b75a
--- /dev/null
+++ b/extra/Makefile
@@ -0,0 +1,128 @@
+# File: Makefile for fuss
+# Location: fuss source package
+# Author: bgstack15
+# Startdate: 2020-12-30
+# Title: Makefile for fuss source package
+# Purpose: To use traditional Unix make utility
+# History:
+# Usage:
+# Reference:
+# hex-zero Makefile
+# Improve:
+# add man page?
+# Document:
+# Dependencies:
+# build-devuan:
+
+APPNAME = fuss
+APPVERSION = 0.0.1
+SRCDIR = $(CURDIR)/..# because Makefile is in extra/ inside this repo
+prefix = /usr
+SYSCONFDIR = $(DESTDIR)/etc
+DEFAULTDIR = $(DESTDIR)/etc/sysconfig# for debian use '$(DESTDIR)/etc/default'
+LIBEXECDIR = $(DESTDIR)$(prefix)/libexec
+SHAREDIR = $(DESTDIR)$(prefix)/share
+DOCDIR = $(SHAREDIR)/doc/$(APPNAME)
+APPDIR = $(SHAREDIR)/$(APPNAME)
+APPVARDIR = $(DESTDIR)/var/www/$(APPNAME)
+MANDIR = $(SHAREDIR)/man
+SYSVDIR = $(SYSCONFDIR)/init.d
+SYSDDIR = $(DESTDIR)$(prefix)/lib/systemd/system
+LOGDIR = $(DESTDIR)/var/log/fuss
+APACHEDIR = $(SYSCONFDIR)/httpd/conf.d# for debian use '$(SYSCONFDIR)/apache2/sites-available'
+CRONDIR = $(SYSCONFDIR)/cron.d
+SBINDIR = $(DESTDIR)$(prefix)/sbin
+
+# variables for deplist
+DEPTYPE = dep
+SEPARATOR = ,
+
+awkbin :=$(shell which awk)
+chmodbin :=$(shell which chmod)
+cpbin :=$(shell which cp)
+echobin :=$(shell which echo)
+falsebin :=$(shell which false)
+findbin :=$(shell which find)
+grepbin :=$(shell which grep)
+gzipbin :=$(shell which gzip)
+installbin :=$(shell which install)
+rmbin :=$(shell which rm)
+rmdirbin :=$(shell which rmdir)
+sedbin :=$(shell which sed)
+sortbin :=$(shell which sort)
+truebin :=$(shell which true)
+uniqbin :=$(shell which uniq)
+xargsbin :=$(shell which xargs)
+
+with_apache ?= YES
+with_init ?= YES
+with_systemd ?= NO
+with_pip_helper ?= NO
+
+all:
+ -@echo "Nothing to build." && ${truebin}
+
+install: install_files
+
+.PHONY: clean install install_files uninstall list deplist deplist_opts
+
+list:
+ @$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | ${awkbin} -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | ${sortbin} | ${grepbin} -E -v -e '^[^[:alnum:]]' -e '^$@$$'
+
+deplist:
+ @# deplist 2020-04-18 input must be comma separated
+ @# DEPTYPE( dep , rec , sug ) for depends, recommends, or suggests
+ @if test -z "${DISTRO}" ; then ${echobin} "Please run \`make deplist\` with DISTRO= one of: `make deplist_opts 2>&1 1>/dev/null | ${xargsbin}`. Aborted." 1>&2 ; exit 1 ; fi
+ @if ! ${echobin} "${DEPTYPE}" | grep -qE "^(dep|rec|sug)$$" ; then ${echobin} "Please run \`make deplist\` with DEPTYPE= one of: dep, rec, sug. Undefined will use \`dep\`. Aborted." 1>&2 ; exit 1; fi
+ @${grepbin} -h --exclude-dir='doc' -riIE "\<${DEPTYPE}-" ${SRCDIR} | ${awkbin} -v "domain=${DISTRO}" -v "deptype=${DEPTYPE}" 'tolower($$2) ~ deptype"-"domain {$$1="";$$2="";print}' | tr ',' '\n' | ${sortbin} | ${uniqbin} | ${sedbin} -r -e 's/^\s*//' -e "s/\s*\$$/${SEPARATOR}/" | ${xargsbin}
+
+deplist_opts:
+ @# deplist_opts 2020-04-18 find all available dependency domains
+ @${grepbin} -h -o -riIE '\<(dep|rec|sug)-[^\ :]+:' ${SRCDIR} | ${sedbin} -r -e 's/(dep|rec|sug)-//;' -e 's/:$$//;' | ${sortbin} | ${uniqbin} 1>&2
+
+install_files:
+ ${installbin} -m0755 -d ${LOGDIR} ${APPVARDIR}/upload ${APPDIR}/static ${APPDIR}/templates \
+ ${DOCDIR} ${SBINDIR} ${SYSCONFDIR} ${LIBEXECDIR}/${APPNAME}
+ ${installbin} -m0755 -t ${SBINDIR} ${SRCDIR}/${APPNAME}.bin
+ ${installbin} -m0644 -t ${LIBEXECDIR}/${APPNAME} ${SRCDIR}/${APPNAME}.py
+ ${installbin} -m0644 ${SRCDIR}/${APPNAME}.conf.example ${SYSCONFDIR}/${APPNAME}.conf
+ ${installbin} -m0644 ${SRCDIR}/${APPNAME}.wsgi.ini.example ${SYSCONFDIR}/${APPNAME}.wsgi.ini
+ ${installbin} -m0644 -t ${DOCDIR} ${SRCDIR}/*.md
+ ${installbin} -m0644 -t ${APPDIR}/static ${SRCDIR}/static/*
+ ${installbin} -m0644 -t ${APPDIR}/templates ${SRCDIR}/templates/*
+ifeq ($(with_apache),YES)
+ ${installbin} -m0755 -d ${APACHEDIR}
+ ${installbin} -m0644 ${SRCDIR}/extra/${APPNAME}.conf.apache ${APACHEDIR}/${APPNAME}.conf
+endif
+ifeq ($(with_init),YES)
+ ${installbin} -m0755 -d ${SYSVDIR}
+ ${installbin} -m0755 ${SRCDIR}/extra/${APPNAME}.init ${SYSVDIR}/${APPNAME}
+endif
+ifeq ($(with_systemd),YES)
+ ${installbin} -m0755 -d ${SYSDDIR}
+ ${installbin} -m0644 ${SRCDIR}/extra/fuss.service -t ${SYSDDIR}
+endif
+ifeq ($(with_pip_helper),YES)
+ ${installbin} -m0755 -t ${LIBEXECDIR}/${APPNAME}/ ${SRCDIR}/extra/pip-helper.sh
+endif
+
+uninstall:
+ @${echobin} SRCDIR=${SRCDIR}
+ ${rmbin} -f ${APPDIR}/${APPNAME}.* \
+ ${DOCDIR}/* \
+ ${APPDIR}/static/* \
+ ${APPDIR}/templates/* \
+ ${LIBEXECDIR}/${APPNAME}/* \
+ ${SBINDIR}/${APPNAME}.bin \
+ 1>/dev/null 2>&1 || :
+ ${rmbin} -f ${APACHEDIR}/${APPNAME}.conf || :
+ ${rmbin} -f ${SYSVDIR}/${APPNAME} || :
+
+ # remove all installed directories that are now blank.
+ ${rmdirbin} ${APPVARDIR}/upload ${APPDIR}/static \
+ ${SYSVDIR} ${APACHEDIR} ${DOCDIR} \
+ ${LIBEXECDIR}/${APPNAME} ${LOGDIR} 2>/dev/null || :
+ ${rmdirbin} ${APPDIR} 2>/dev/null || :
+
+clean:
+ -@${echobin} "target $@ not implemented yet! Gotta say unh." && ${falsebin}
diff --git a/extra/fuss-el7.patch b/extra/fuss-el7.patch
new file mode 100644
index 0000000..3a9ceed
--- /dev/null
+++ b/extra/fuss-el7.patch
@@ -0,0 +1,28 @@
+Summary: Make changes necessary for this package to work on CentOS 7
+Message: Correct name of python36 wsgi plugin, and disable icons
+Date: 2021-01-05
+diff master/fuss.wsgi.ini.example el7/fuss.wsgi.ini.example
+index 42ebfe2..75b59bb 100644
+--- a/fuss.wsgi.ini.example
++++ b/fuss.wsgi.ini.example
+@@ -2,7 +2,7 @@
+ # References:
+ # https://uwsgi-docs.readthedocs.io/en/latest/Logging.html
+ [uwsgi]
+-plugins = python3,logfile
++plugins = python36,logfile
+ http-socket = 0.0.0.0:5003
+ wsgi-file = /usr/libexec/fuss/fuss.py
+ callable = app
+--- a/fuss.conf.example 2021-01-05 22:20:05.102222226 -0500
++++ b/fuss.conf.example 2021-01-05 22:24:51.642095995 -0500
+@@ -52,7 +52,7 @@
+ ]
+
+ # Include mimetype icon support on html-long. This requires META = True
+-ICONS = True
++ICONS = False
+ ICON_THEME = "Numix"
+
+ # for in-app adjustments of logging, see project [hex-zero](https://gitlab.com/bgstack15/hex-zero/-/tree/stack) which has limited ability to affect logging.
+
diff --git a/extra/fuss.conf.apache b/extra/fuss.conf.apache
new file mode 100644
index 0000000..661b708
--- /dev/null
+++ b/extra/fuss.conf.apache
@@ -0,0 +1,60 @@
+# Apache example config for fuss application
+<VirtualHost *:80>
+
+ ServerName d2-03a.ipa.example.com
+
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+
+ #LogLevel info ssl:warn
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+ CustomLog ${APACHE_LOG_DIR}/access.log combined
+
+ # OPTION 1: send to https
+ # force https for this path
+ RewriteEngine On
+ RewriteCond %{HTTPS} !=on
+ RewriteCond %{HTTP_HOST} !^(localhost|127.0.0.1)
+ RewriteRule ^/fuss(.*) https://%{SERVER_NAME}/fuss$1 [R,L]
+
+ # OPTION 2: Just use unencrypted
+ #ProxyPass /fuss http://localhost:5003/
+ #ProxyPassReverse /fuss http://localhost:5003/
+ #<Location /fuss>
+ # RequestHeader append X-Forwarded-Prefix "/fuss"
+ # RequestHeader set X-Forwarded-Proto "http"
+ #</Location>
+
+</VirtualHost>
+
+# To use OPTION 2 above, just disable this whole 443 virtualhost.
+<VirtualHost *:443>
+ ServerName d2-03a.ipa.example.com
+
+ ServerAdmin webmaster@localhost
+ DocumentRoot /var/www/html
+
+ #LogLevel info ssl:warn
+
+ ErrorLog ${APACHE_LOG_DIR}/ssl-error.log
+ CustomLog ${APACHE_LOG_DIR}/ssl-access.log combined
+
+ SSLEngine on
+ SSLProtocol all -SSLv2 -SSLv3
+ SSLHonorCipherOrder on
+ SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA !RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"
+
+ SSLCertificateFile /etc/ssl/private/https-d2-03a.ipa.example.com.pem
+ SSLCertificateKeyFile /etc/ssl/private/https-d2-03a.ipa.example.com-nopw.key
+
+ ProxyPass /fuss http://localhost:5003/
+ ProxyPassReverse /fuss http://localhost:5003/
+ <Location /fuss>
+ # a2enmod headers. These are extra ones that are not provided by Apache natively.
+ RequestHeader append X-Forwarded-Prefix "/fuss"
+ RequestHeader set X-Forwarded-Proto "https"
+ </Location>
+
+</VirtualHost>
+# vim:set syntax=apache ts=3 sw=3 sts=3 sr noet:
diff --git a/extra/fuss.init b/extra/fuss.init
new file mode 100755
index 0000000..7a7b5d7
--- /dev/null
+++ b/extra/fuss.init
@@ -0,0 +1,172 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides: fuss
+# Required-Start: $local_fs $network $remote_fs $syslog
+# Required-Stop: $local_fs $network $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: File Upoad and Storage Service
+# Description: Python3 Flask application that presents a basic file hosting service
+### END INIT INFO
+
+# Author: B. Stack <bgstack15@gmail.com>
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+DAEMON_ARGS=""
+DAEMON=/usr/sbin/fuss.bin
+DESC="fuss"
+NAME=fuss
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+PIDFILE2=/var/www/fuss/fuss.pid
+PIDFILE=/var/run/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+USER=fuss
+WSGIBIN=uwsgi_python39
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
+# and status_of_proc is working.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+ # Return
+ # 0 if daemon has been started
+ # 1 if daemon was already running
+ # 2 if daemon could not be started
+ #start-stop-daemon --start --quiet --chuid $USER --group $USER --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
+ # || return 1
+ #start-stop-daemon --start --quiet --chuid $USER --group $USER --background --pidfile $PIDFILE --exec $DAEMON -- \
+ # $DAEMON_ARGS \
+ # || return 2
+ #su $USER -c "$DAEMON" &
+ # The above code will not work for interpreted scripts, use the next
+ # six lines below instead (Ref: #643337, start-stop-daemon(8) )
+ start-stop-daemon --start --make-pidfile --pidfile $PIDFILE \
+ --chuid $USER --group $USER \
+ --startas $DAEMON \
+ --name $WSGIBIN --test > /dev/null \
+ || return 1
+ start-stop-daemon --start --background --make-pidfile --pidfile $PIDFILE --startas $DAEMON \
+ --chuid $USER --group $USER \
+ --name $WSGIBIN -- $DAEMON_ARGS \
+ || return 2
+
+ # Add code here, if necessary, that waits for the process to be ready
+ # to handle requests from services started subsequently which depend
+ # on this one. As a last resort, sleep for some time.
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+ # Return
+ # 0 if daemon has been stopped
+ # 1 if daemon was already stopped
+ # 2 if daemon could not be stopped
+ # other if a failure occurred
+ #start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --user $USER --pidfile $PIDFILE
+ /usr/bin/$WSGIBIN --stop $PIDFILE2 2>/dev/null
+ RETVAL="$?"
+ [ "$RETVAL" = 2 ] && return 2
+ # Wait for children to finish too if this is a daemon that forks
+ # and if the daemon is only ever run from this initscript.
+ # If the above conditions are not satisfied then add some other code
+ # that waits for the process to drop all resources that could be
+ # needed by services started subsequently. A last resort is to
+ # sleep for some time.
+ start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --user $USER --pidfile $PIDFILE
+ [ "$?" = 2 ] && return 2
+ # Many daemons don't delete their pidfiles when they exit.
+ rm -f $PIDFILE
+ return "$RETVAL"
+}
+
+#
+# Function that sends a SIGHUP to the daemon/service
+#
+do_reload() {
+ #
+ # If the daemon can reload its configuration without
+ # restarting (for example, when it is sent a SIGHUP),
+ # then implement that here.
+ #
+ start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $WSGIBIN
+ return 0
+}
+
+case "$1" in
+ start)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+ do_start
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ stop)
+ [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+ 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+ esac
+ ;;
+ status)
+ status_of_proc -p $PIDFILE "$DAEMON" "$NAME" && exit 0 || exit $?
+ ;;
+ #reload|force-reload)
+ #
+ # If do_reload() is not implemented then leave this commented out
+ # and leave 'force-reload' as an alias for 'restart'.
+ #
+ #log_daemon_msg "Reloading $DESC" "$NAME"
+ #do_reload
+ #log_end_msg $?
+ #;;
+ restart|force-reload)
+ #
+ # If the "reload" option is implemented then remove the
+ # 'force-reload' alias
+ #
+ log_daemon_msg "Restarting $DESC" "$NAME"
+ do_stop
+ case "$?" in
+ 0|1)
+ do_start
+ case "$?" in
+ 0) log_end_msg 0 ;;
+ 1) log_end_msg 1 ;; # Old process is still running
+ *) log_end_msg 1 ;; # Failed to start
+ esac
+ ;;
+ *)
+ # Failed to stop
+ log_end_msg 1
+ ;;
+ esac
+ ;;
+ *)
+ #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+ echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2
+ exit 3
+ ;;
+esac
+
+:
diff --git a/extra/fuss.service b/extra/fuss.service
new file mode 100644
index 0000000..709ded6
--- /dev/null
+++ b/extra/fuss.service
@@ -0,0 +1,20 @@
+[Unit]
+Description=File Upload and Storage Service
+Wants=network-online.target
+After=network.target syslog.target
+
+[Service]
+#Environment=
+WorkingDirectory=/var/www/fuss
+User=fuss
+Group=fuss
+Type=simple
+ExecStart=/usr/sbin/fuss.bin
+TimeoutStartSec=120
+ExecStop=/usr/sbin/uwsgi --stop /var/www/fuss/fuss.pid
+RestartSec=15
+Restart=always
+KillSignal=SIGINT
+
+[Install]
+WantedBy=multi-user.target
diff --git a/extra/fuss.spec b/extra/fuss.spec
new file mode 100644
index 0000000..3519216
--- /dev/null
+++ b/extra/fuss.spec
@@ -0,0 +1,167 @@
+# File: fuss.spec
+# Location: fuss package
+# Author: bgstack15
+# SPDX-License-Identifier: CC-BY-SA-4.0
+# Startdate: 2021-01-05
+# Title: Rpm spec for fuss package
+# Purpose: Provide build instructions for CentOS rpm for package
+# History:
+# Usage:
+# Reference:
+# Improve:
+# Documentation:
+# Dependencies:
+
+# Tunables
+# If you set with_icons to 1, then you will pull in a large amount of dependencies!
+%global with_icons 0
+# If you set this to 1, use the systemd-rpm-macros functionality described at https://docs.fedoraproject.org/en-US/packaging-guidelines/UsersAndGroups/
+%global with_systemd_usercreate 0
+%global pythonver python36
+
+# Fedora defaults
+%if 0%{?fedora}
+%global with_systemd_usercreate 1
+%global with_icons 1
+%global pythonver python3
+%endif
+
+%global _appvardir %{?_localstatedir}%{!?_localstatedir:/var}/www/fuss
+%global _appdir %{?_datarootdir}%{!?_datarootdir:%{_prefix}/share}/fuss
+%global _user fuss
+
+%define devtty "/dev/null"
+%define debug_package %{nil}
+%global _python_bytecompile_errors_terminate_build 0
+
+Summary: file upload and storage service web app
+Name: fuss
+Version: 0.0.1
+Release: 1
+License: GPL 3.0
+Source0: %{name}_%{version}.orig.tar.gz
+%if 0%{?with_systemd_usercreate}
+Source1: extra/%{name}.sysusers
+%endif
+%if ! 0%{?fedora}
+Patch1: extra/%{name}-el7.patch
+%endif
+URL: https://bgstack15.wordpress.com/
+#Distribution:
+#Vendor:
+Packager: B. Stack <bgstack15@gmail.com>
+Requires: %{pythonver}-flask
+Requires: %{pythonver}-uwsgidecorators
+Requires: uwsgi-plugin-%{pythonver}
+Requires: uwsgi-logger-file
+%if 0%{?fedora}
+Requires: %{pythonver}-magic
+Requires: %{pythonver}-flask-script
+%endif
+# Mandatory pip3 requirements: flask-script, python-magic
+%if 0%{?with_icons}
+Requires: /usr/bin/xvfb-run
+%if 0%{?fedora}
+Requires: %{pythonver}-gobject
+%else
+# The following are needed for CentOS7 pip3 install --user PyGObject
+Requires: cairo-gobject-devel
+Requires: gcc
+Requires: gobject-introspection-devel
+Requires: gtk3-devel
+Requires: python36-gobject
+Requires: python3-devel
+%endif
+%endif
+#BuildRequires: txt2man
+%if 0%{?with_systemd_usercreate}
+BuildRequires: systemd-rpm-macros
+%endif
+%if 0%{?fedora} || 0%{?rhel} >= 8
+Suggests: httpd
+%endif
+Buildarch: noarch
+
+%description
+File Upload and Storage Service is a demo flask application that can
+be used for whatever purposes you want.
+
+%prep
+%setup -q -c %{name}
+test -d "%{name}" && cd "%{name}"
+%if ! 0%{?fedora}
+%patch1 -p1
+%endif
+
+%build
+export srcdir="extra"
+test -d "%{name}" && cd "%{name}"
+%make_build -C "${srcdir}"
+
+%install
+export srcdir="extra"
+test -d "%{name}" && cd "%{name}"
+%make_install -C "${srcdir}" \
+ with_systemd=YES \
+ with_init=NO \
+ with_pip_helper=YES
+%if 0%{?with_systemd_usercreate}
+install -p -D -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/%{name}.conf
+%endif
+exit 0
+
+%clean
+rm -rf %{buildroot}
+
+%pre
+# Reference: squid.spec
+%if 0%{?with_systemd_usercreate}
+%sysusers_create_compat %{SOURCE1}
+%else
+if ! getent group %{_user} 1>/dev/null 2>&1 ;
+then
+ /usr/sbin/groupadd --system --gid 723 %{_user}
+fi
+if ! getent passwd %{_user} 1>/dev/null 2>&1 ;
+then
+ /usr/sbin/useradd --system --gid 723 \
+ --uid 723 --comment "FUSS system user" \
+ --home-dir %{_appvardir} --shell /sbin/nologin \
+ %{_user}
+fi
+%endif
+exit 0
+
+%preun
+%systemd_postun_with_restart %{name}.service
+
+%post
+%systemd_post %{name}.service
+
+%postun
+%systemd_postun_with_restart %{name}.service
+
+%files
+%if 0%{?with_systemd_usercreate}
+%{_sysusersdir}/%{name}.conf
+%endif
+%attr(0644, %{_user}, %{_user}) %config(noreplace) %{_sysconfdir}/%{name}.conf
+%attr(0644, %{_user}, %{_user}) %config(noreplace) %{_sysconfdir}/%{name}.wsgi.ini
+%attr(0644, %{_user}, %{_user}) %{_libexecdir}/%{name}/%{name}.py
+%attr(0755, %{_user}, %{_user}) %{_sbindir}/%{name}.bin
+%attr(0644, %{_user}, %{_user}) %{_appdir}/static/*
+%attr(0644, %{_user}, %{_user}) %{_appdir}/templates/*
+%attr(0755, %{_user}, %{_user}) %dir %{_appdir}/static
+%attr(0755, %{_user}, %{_user}) %dir %{_appdir}/templates
+%attr(0755, %{_user}, %{_user}) %dir %{_appvardir}/upload
+%attr(0755, %{_user}, %{_user}) %dir %{_appdir}
+%attr(0755, %{_user}, %{_user}) %dir %{_appvardir}
+%attr(0755, -, -) %{_libexecdir}/%{name}/pip-helper.sh
+%attr(0644, root, root) %{?_unitdir}%{!?_unitdir:/usr/lib/systemd/system}/%{name}.service
+%attr(0644, root, root) %{_sysconfdir}/httpd/conf.d/%{name}.conf
+%attr(0755, %{_user}, %{_user}) %dir %{?_localstatedir}%{!?_localstatedir:/var}/log/%{name}
+%{_defaultdocdir}/%{name}
+
+%changelog
+* Tue Jan 05 2021 B. Stack <bgstack15@gmail.com> - 0.0.1-1
+- Initial release
diff --git a/extra/fuss.sysusers b/extra/fuss.sysusers
new file mode 100644
index 0000000..e9f60df
--- /dev/null
+++ b/extra/fuss.sysusers
@@ -0,0 +1,3 @@
+# Part of fuss package
+#Type Name ID GECOS Home directory Shell
+u fuss - "FUSS system user" /var/www/fuss /sbin/nologin
diff --git a/extra/pip-helper.sh b/extra/pip-helper.sh
new file mode 100644
index 0000000..39213aa
--- /dev/null
+++ b/extra/pip-helper.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+# This file is part of the fuss package.
+# It is designed to be run as root, and it will run the requisite pip commands for the discovered environment.
+
+contents="$( awk -F'=' '/ID=|VERSION_ID/{print $2}' /etc/os-release 2>/dev/null | sed -r -e 's/"//g;' )"
+id="$( echo "${contents}" | sed -n -e '1p' )"
+version_id="$( echo "${contents}" | sed -n -e '2p' )"
+
+echo "Any parameters sent to this script ${0} will be added to the list of packages to install."
+echo "This is particularly useful for adding the PyGObject for icon support on EL7."
+piplist="${1}"
+
+if echo "${id}" | grep -qiE 'rhel|centos' ;
+then
+ if echo "${version_id}" | grep -qiE '7' ;
+ then
+ piplist="${piplist} flask-script python-magic"
+ fi
+else
+ echo "Unknown os from /etc/os-release. Please investigate what pip3" 1>&2
+ echo "packages are required for this OS release and share it with upstream." 1>&2
+ echo "Aborted." 1>&2
+ exit 1
+fi
+
+if test -n "${piplist}" ;
+then
+ echo "Will try to serially install with pip these packages: ${piplist}"
+ for word in ${piplist} ; do
+ su fuss -s /bin/sh -c "pip3 install --user ${word}" || exit 1
+ done
+fi
bgstack15