This is an automated email from the ASF dual-hosted git repository.

fgerlits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git

commit 3a78be611b59f381941c30803a833dbf4abdfa2c
Author: Marton Szasz <[email protected]>
AuthorDate: Fri Aug 11 05:08:15 2023 +0200

    MINIFICPP-2181 Use systemd service management on Linux
    
    I generated small parts of this PR with GitHub Copilot. I believe all of the
    generated snippets are trivial enough to not be copyrightable in their own
    right, and I would have written the same myself. For this reason, I believe
    that I own the copyright for the whole code, and it can be licensed under 
the
    Apache License 2.0.
    
    Signed-off-by: Ferenc Gerlits <[email protected]>
    This closes #1627
---
 .gitignore                                      |   1 -
 CMakeLists.txt                                  |   2 +-
 README.md                                       |  16 +-
 bin/minifi.service                              |  16 ++
 bin/minifi.sh                                   | 356 +++---------------------
 docker/test/integration/features/steps/steps.py |   2 +-
 6 files changed, 69 insertions(+), 324 deletions(-)

diff --git a/.gitignore b/.gitignore
index b917c99b8..38cd99d85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -49,7 +49,6 @@ cmake-build-debug
 build
 /*build*
 bt_state
-bin
 target
 thirdparty/**/*.o
 thirdparty/**/*.a
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 17ea231da..13a2b9924 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -541,7 +541,7 @@ if (NOT WIN32)
         DESTINATION minifi-python
         COMPONENT bin)
 
-    install(PROGRAMS bin/minifi.sh
+    install(PROGRAMS bin/minifi.sh bin/minifi.service
         DESTINATION bin
         COMPONENT bin)
 endif()
diff --git a/README.md b/README.md
index 060eacddf..df1a6ad72 100644
--- a/README.md
+++ b/README.md
@@ -501,12 +501,18 @@ $ cd nifi-minifi-cpp-*
 ### Configuring
 The 'conf' directory in the installation root contains a template config.yml 
document, minifi.properties, and minifi-log.properties. Please see our 
[Configuration document](CONFIGURE.md) for details on how to configure agents.
 
+### Installing as a service
+
+MiNiFi can also be installed as a system service using minifi.sh:
+
+    $ ./bin/minifi.sh install
+
 ### Running
-After completing the [installation](#installation), the application can be run 
by issuing the following command from the installation directory:
+After completing the [installation](#installing-as-a-service), the application 
can be run by issuing the following command from the installation directory:
 
     $ ./bin/minifi.sh start
 
-By default, this will make use of a config.yml located in the conf directory.  
This configuration file location can be altered by adjusting the property 
`nifi.flow.configuration.file` in minifi.properties located in the conf 
directory.
+By default, this will make use of a config.yml located in the conf directory. 
This configuration file location can be altered by adjusting the property 
`nifi.flow.configuration.file` in minifi.properties located in the conf 
directory.
 
 ### Stopping
 
@@ -514,12 +520,6 @@ MiNiFi can then be stopped by issuing:
 
     $ ./bin/minifi.sh stop
 
-### Installing as a service
-
-MiNiFi can also be installed as a system service using minifi.sh with an 
optional "service name" (default: minifi)
-
-    $ ./bin/minifi.sh install [service name]
-
 ### Running as a docker container
 You can use the officially released image pulled from the 
[apache/nifi-minifi-cpp](https://hub.docker.com/r/apache/nifi-minifi-cpp) 
repository on dockerhub or you can use your locally built image.
 The container can be run with a specific configuration by mounting the locally 
edited configuration files to your docker container.
diff --git a/bin/minifi.service b/bin/minifi.service
new file mode 100644
index 000000000..6f3c43908
--- /dev/null
+++ b/bin/minifi.service
@@ -0,0 +1,16 @@
+[Unit]
+Description=Starts and stops the MiNiFi C++ Agent
+After=network.target
+
+[Service]
+Type=simple
+Environment=MINIFI_HOME=/opt/minifi-cpp
+ExecStart=/opt/minifi-cpp/bin/minifi
+Restart=on-failure
+RestartSec=3
+KillSignal=SIGTERM
+TimeoutStopSec=20
+RestartForceExitStatus=3
+
+[Install]
+WantedBy=multi-user.target
diff --git a/bin/minifi.sh b/bin/minifi.sh
index 2e074e4c5..33a395a53 100755
--- a/bin/minifi.sh
+++ b/bin/minifi.sh
@@ -23,7 +23,6 @@ MINIFI_HOME="$(dirname "${SCRIPTPATH}")"
 export MINIFI_HOME
 bin_dir=${MINIFI_HOME}/bin
 minifi_executable=${bin_dir}/minifi
-pid_file=${bin_dir}/.minifi.pid
 
 warn() {
     echo "${PROGNAME}: $*"
@@ -57,352 +56,83 @@ detectOS() {
     fi
 }
 
-init() {
-    # Determine if there is special OS handling we must perform
-    detectOS
-}
-
-# determines the pid
-get_pid() {
-  # Default to a -1 for pid
-  pid=-1
-  # Check to see if we have a pid file
-  if [ -f "${pid_file}" ]; then
-    pid=$(cat "${pid_file}")
-  fi
-  echo "${pid}"
-}
-
-# Performs a check to see if the provided pid is one that currently exists
-active_pid() {
-  pid=${1}
-  if [ "${pid}" -eq -1 ]; then
-    echo 1
-  elif [ "${pid}" -eq $$ ]; then
-    echo 1
-  else
-    kill -s 0 "${pid}" > /dev/null 2>&1
-    echo $?
-  fi
-}
-
-endnow() {
-   echo "Killing MiNiFi..."
-   kill -9 "${saved_pid}" > /dev/null 2>&1
-
-}
-
 install() {
     detectOS
-
     if [ "${darwin}" = "true"  ] || [ "${cygwin}" = "true" ]; then
         echo 'Installing Apache MiNiFi as a service is not supported on OS X 
or Cygwin.'
         exit 1
     fi
 
-    SVC_NAME=minifi
-    if [ "x$2" != "x" ] ; then
-        SVC_NAME=$2
-    fi
+    echo "Uninstalling any previous versions"
+    uninstall
+
+    target_dir="/usr/local/lib/systemd/system"
+    mkdir -p "${target_dir}" || die "Unable to create ${target_dir}. Cannot 
install MiNiFi as a service."
 
-    initd_dir='/etc/init.d'
-    SVC_FILE="${initd_dir}/${SVC_NAME}"
+    echo "Installing MiNiFi as a systemd service to ${target_dir}"
+    cp -fv "${bin_dir}"/minifi.service "${target_dir}"
+    chmod 644 "${target_dir}"/minifi.service
+    sed -i "s|/opt/minifi-cpp|${MINIFI_HOME}|g" "${target_dir}"/minifi.service
+    systemctl daemon-reload
+    systemctl enable minifi.service
+}
 
-    if [ ! -w  "${initd_dir}" ]; then
-        echo "Current user does not have write permissions to ${initd_dir}. 
Cannot install MiNiFi as a service."
+uninstall() {
+    detectOS
+    if [ "${darwin}" = "true"  ] || [ "${cygwin}" = "true" ]; then
+        echo 'Apache MiNiFi as a service is not supported on OS X or Cygwin.'
         exit 1
     fi
 
-# Create the init script, overwriting anything currently present
-cat <<SERVICEDESCRIPTOR > "${SVC_FILE}"
-#!/bin/sh
-#
-#    Licensed to the Apache Software Foundation (ASF) under one or more
-#    contributor license agreements.  See the NOTICE file distributed with
-#    this work for additional information regarding copyright ownership.
-#    The ASF licenses this file to You under the Apache License, Version 2.0
-#    (the "License"); you may not use this file except in compliance with
-#    the License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS,
-#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#    See the License for the specific language governing permissions and
-#    limitations under the License.
-#
-# chkconfig: 2345 20 80
-# description: Apache NiFi MiNiFi is a subproject of Apache nifi to collect 
data where it originates.
-#
-# Make use of the configured MINIFI_HOME directory and pass service requests 
to the minifi executable
-export MINIFI_HOME=${MINIFI_HOME}
-bin_dir=\${MINIFI_HOME}/bin
-minifi_executable=\${bin_dir}/minifi
-pid_file="\${bin_dir}/.minifi.pid"
-
-# determines the pid
-get_pid() {
-  # Default to a -1 for pid
-  pid=-1
-  # Check to see if we have a pid file
-  if [ -f \${pid_file} ]; then
-    pid=\$(cat "\${pid_file}")
-  fi
-  echo \${pid}
-}
+    # Uninstall legacy init.d service files, if exists
+    rm -fv "/etc/init.d/minifi" || :
+    rm -fv "/etc/rc2.d/S65minifi" || :
+    rm -fv "/etc/rc2.d/K65minifi" || :
 
-# Performs a check to see if the provided pid is one that currently exists
-active_pid() {
-  pid=\${1}
-  if [ \${pid} -eq -1 ]; then
-    echo 1
-  elif [ "${pid}" -eq $$ ]; then
-    echo 1
-  else
-    kill -s 0 \${pid} > /dev/null 2>&1
-    echo \$?
-  fi
+    # Uninstall systemd service files, if exists
+    rm -fv "/usr/local/lib/systemd/system/minifi.service" || :
+    systemctl daemon-reload
 }
 
-saved_pid=\$(get_pid)
-
-case "\$1" in
-    start)
-      if [ "\${saved_pid}" -gt 0 ]; then
-        if [ \$(active_pid \${saved_pid}) -ne 0 ]; then
-            echo "PID \${saved_pid} is stale, removing pid file at 
\${pid_file}";
-            if ! rm -f \${pid_file}; then
-              echo "Could not remove \${pid_file}. File will need to be 
manually removed."
-              exit 1;
-            fi
-        else
-            echo "MINIFI is currently running (PID: \${saved_pid}) with pid 
file \${pid_file}."
-            exit 0;
-        fi
-      fi
-      \${minifi_executable} &
-      pid=\$!
-      echo \${pid} > \${pid_file}
-      echo Starting MiNiFi with PID \${pid} and pid file \${pid_file}
-      ;;
-    stop)
-      if [ \$(active_pid \${saved_pid}) -ne 0 ]; then
-        echo "MiNiFi is not currently running."
-      else
-        echo "Stopping MiNiFi (PID: \${saved_pid})."
-        # Send a SIGTERM to MiNiFi so that the handler begins shutdown.
-        kill -15 \${saved_pid} > /dev/null 2>&1
-        if [ \$? -ne 0 ]; then
-          echo "Could not successfully send termination signal to MiNiFi (PID: 
\${saved_pid})"
-          exit 1;
-        else
-          # Clean up our pid file
-          rm -f \${pid_file}
-        fi
-      fi
-      ;;
-    run)
-      if [ "\${saved_pid}" -gt 0 ]; then
-        if ! active_pid \${saved_pid}; then
-            echo "PID \${saved_pid} is stale, removing pid file at 
\${pid_file}";
-            if ! rm -f \${pid_file}; then
-              echo "Could not remove \${pid_file}. File will need to be 
manually removed."
-              exit 1;
-            fi
-        else
-            echo "MINIFI is currently running (PID: \${saved_pid}) with pid 
file \${pid_file}."
-            exit 0;
-        fi
-      fi
-      pid=$$
-      echo ${pid} > "${pid_file}"
-      exec "\${minifi_executable}"
-      ;;
-    status)
-        # interpret status as per LSB specifications
-        # see:  
http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
-
-        if [ "\${saved_pid}" -gt 0 ]; then
-          if [ \$(active_pid \${saved_pid}) -ne 0 ]; then
-            # program is dead and pid file exists
-            echo "Program is not currently running but stale pid file 
(\${pid_file}) exists.";
-            exit 1
-          else
-            # pid is correct, program is running
-            echo "MINIFI is currently running (PID: \${saved_pid}) with pid 
file \${pid_file}."
-            exit 0;
-          fi
-        else
-          # program is not running
-          echo "MiNiFi is not currently running."
-          exit 3;
-        fi
-        ;;
-     update)
-        if [  -f \${bin_dir}/minifi.update ]; then
-                \${bin_dir}/minifi.sh stop
-                cp \${bin_dir}/minifi \${bin_dir}/minifi.bak
-             cp \${bin_dir}/minifi.update \${bin_dir}/minifi
-             # ensure that the command is now running
-             \${bin_dir}/minifi.sh start
-             saved_pid=\$(get_pid)
-             if [ "\${saved_pid}" -gt 0 ]; then
-                   if [ \$(active_pid \${saved_pid}) -ne 0 ]; then
-                       cp \${bin_dir}/minifi.bak \${bin_dir}/minifi
-                               \${bin_dir}/minifi.sh start
-                   fi
-                fi
-               fi
-        ;;
-    restart)
-      echo "Restarting the MiNiFi service. Hit CTRL+C at any time to forcibly 
terminate MiNiFi"
-      "\${bin_dir}/minifi.sh" stop
-      ticks=1
-      printf "Waiting for process to terminate."
-      trap endnow INT
-      if [ "\${saved_pid}" -gt 0 ]; then
-        while [ "\$(active_pid \${saved_pid})" -eq 0 ]; do
-                sleep 1
-                ticks="\$((ticks+1))"
-                numticks="\$((ticks % 5))"
-                if [ "\${numticks}"  -eq 0 ]; then
-                        printf "."
-                fi
-        done
-      fi
-      "\${bin_dir}/minifi.sh" start
-       ;;
-    *)
-        echo "Usage: service minifi {start|stop|restart|status}"
-        ;;
-esac
-
-SERVICEDESCRIPTOR
-
-    if [ ! -f "${SVC_FILE}" ]; then
-        echo "Could not create service file ${SVC_FILE}"
+check_service_installed() {
+    if [ ! -f "/usr/local/lib/systemd/system/minifi.service" ]; then
+        echo "MiNiFi is not installed as a service. Please run 'minifi.sh 
install' first."
         exit 1
     fi
-
-    # Provide the user execute access on the file
-    chmod u+x "${SVC_FILE}"
-
-    rm -f "/etc/rc2.d/S65${SVC_NAME}"
-    ln -s "/etc/init.d/${SVC_NAME}" "/etc/rc2.d/S65${SVC_NAME}" || { echo 
"Could not create link /etc/rc2.d/S65${SVC_NAME}"; exit 1; }
-    rm -f "/etc/rc2.d/K65${SVC_NAME}"
-    ln -s "/etc/init.d/${SVC_NAME}" "/etc/rc2.d/K65${SVC_NAME}" || { echo 
"Could not create link /etc/rc2.d/K65${SVC_NAME}"; exit 1; }
-    echo "Service ${SVC_NAME} installed"
 }
 
-saved_pid=$(get_pid)
-
 case "$1" in
     start)
-      if [ "${saved_pid}" -gt 0 ]; then
-        if [ "$(active_pid "${saved_pid}")" -ne 0 ]; then
-            echo "PID ${saved_pid} is stale, removing pid file at ${pid_file}";
-            if ! rm -f "${pid_file}"; then
-              echo "Could not remove ${pid_file}. File will need to be 
manually removed."
-              exit 1;
-            fi
-        else
-            echo "MINIFI is currently running (PID: ${saved_pid}) with pid 
file ${pid_file}."
-            exit 0;
-        fi
-      fi
-      ${minifi_executable} &
-      pid=$!
-      echo ${pid} > "${pid_file}"
-      echo "Starting MiNiFi with PID ${pid} and pid file ${pid_file}"
+      check_service_installed
+      systemctl start minifi.service
+      echo "MiNiFi started"
       ;;
     stop)
-      if [ "$(active_pid "${saved_pid}")" -ne 0 ]; then
-        echo "MiNiFi is not currently running."
-      else
-        echo "Stopping MiNiFi (PID: ${saved_pid})."
-        # Send a SIGTERM to MiNiFi so that the handler begins shutdown.
-        if ! kill -15 "${saved_pid}" > /dev/null 2>&1; then
-          echo "Could not successfully send termination signal to MiNiFi (PID: 
${saved_pid})"
-          exit 1;
-        else
-          # Clean up our pid file
-          rm -f "${pid_file}"
-        fi
-      fi
+      check_service_installed
+      systemctl stop minifi.service
+      echo "MiNiFi stopped"
       ;;
     run)
-      if [ "${saved_pid}" -gt 0 ]; then
-        if [ "$(active_pid "${saved_pid}")" -ne 0 ]; then
-            echo "PID ${saved_pid} is stale, removing pid file at ${pid_file}";
-            if ! rm -f "${pid_file}"; then
-              echo "Could not remove ${pid_file}. File will need to be 
manually removed."
-              exit 1;
-            fi
-        else
-            echo "MINIFI is currently running (PID: ${saved_pid}) with pid 
file ${pid_file}."
-            exit 0;
-        fi
-      fi
-      pid=$$
-      echo ${pid} > "${pid_file}"
       exec "${minifi_executable}"
       ;;
     status)
-      if [ "${saved_pid}" -gt 0 ]; then
-        if [ "$(active_pid "${saved_pid}")" -ne 0 ]; then
-          # program is dead and pid file exists
-          echo "Program is not currently running but stale pid file 
(${pid_file}) exists.";
-          exit 1
-        else
-          # pid is correct, program is running
-          echo "MINIFI is currently running (PID: ${saved_pid}) with pid file 
${pid_file}."
-          exit 0;
-        fi
-      else
-        # program is not running
-        echo "MiNiFi is not currently running."
-        exit 0;
-      fi
+      check_service_installed
+      systemctl status minifi.service
       ;;
-    update)
-        if [ -f "${bin_dir}"/minifi.update ]; then
-                "${bin_dir}"/minifi.sh stop
-                cp "${bin_dir}"/minifi "${bin_dir}"/minifi.bak
-             cp "${bin_dir}"/minifi.update "${bin_dir}"/minifi
-             # ensure that the command is now running
-             "${bin_dir}"/minifi.sh start
-             saved_pid=$(get_pid)
-             if [ "${saved_pid}" -gt 0 ]; then
-                   if [ "$(active_pid "${saved_pid}")" -ne 0 ]; then
-                       cp "${bin_dir}"/minifi.bak "${bin_dir}"/minifi
-                               "${bin_dir}"/minifi.sh start
-                   fi
-                fi
-               fi
-        ;;
     restart)
-      echo "Restarting MiNiFi. Hit CTRL+C at any time to forcibly terminate 
MiNiFi"
-      "${bin_dir}"/minifi.sh stop
-      ticks=1
-      printf "Waiting for process to terminate."
-      trap endnow INT
-      if [ "${saved_pid}" -gt 0 ]; then
-       while [ "$(active_pid "${saved_pid}")" -eq 0 ]; do
-               sleep 1
-               ticks=$((ticks+1))
-               numticks=$((ticks % 5))
-               if [ "${numticks}"  -eq 0 ]; then
-                       printf "."
-               fi
-        done
-      fi
-      "${bin_dir}"/minifi.sh start
+      check_service_installed
+      systemctl restart minifi.service
+      echo "MiNiFi restarted"
       ;;
     install)
       install "$@"
+      echo "Service minifi installed. Please start it using 'minifi.sh start' 
or 'systemctl start minifi.service'"
+      ;;
+    uninstall)
+      uninstall "$@"
+      echo "Service minifi uninstalled. Please remove the ${MINIFI_HOME} 
directory manually."
       ;;
     *)
-      echo "Usage: minifi.sh {start|stop|run|restart|status|install}"
+      echo "Usage: minifi.sh {start|stop|run|restart|status|install|uninstall}"
       ;;
 esac
diff --git a/docker/test/integration/features/steps/steps.py 
b/docker/test/integration/features/steps/steps.py
index b52862ffa..cb4094d48 100644
--- a/docker/test/integration/features/steps/steps.py
+++ b/docker/test/integration/features/steps/steps.py
@@ -335,7 +335,7 @@ def step_impl(context, flow_name):
 
 @given("a transient MiNiFi flow with the name \"{flow_name}\" is set up")
 def step_impl(context, flow_name):
-    context.test.acquire_container(context=context, name=flow_name, 
command=["/bin/sh", "-c", "./bin/minifi.sh start && sleep 10 && ./bin/minifi.sh 
stop && sleep 100"])
+    context.test.acquire_container(context=context, name=flow_name, 
command=["/bin/sh", "-c", "timeout 10s ./bin/minifi.sh run && sleep 100"])
 
 
 @given("the provenance repository is enabled in MiNiFi")

Reply via email to