Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Optionally) run ncp apps in tmux #796

Open
wants to merge 22 commits into
base: devel
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c9768d2
library: Optionally execute ncp-app in tmux if set in app cfg
Feb 8, 2019
0dbc586
library: Fix return value not being retrieved from tmux'ed script
Feb 8, 2019
d91a5f5
update/install: Install tmux and dependencies on installation/update
Feb 8, 2019
a3c2edf
library: Fix formatting
Feb 8, 2019
88ed633
library: Fix valid return values from tmux not being accepted
Feb 8, 2019
33f44f8
Separate function for attaching to running ncp app's tmux session.
Feb 10, 2019
d707807
ncp-launcher.sh: Add parameter to check if an ncp-app is running
Feb 16, 2019
8bf2d85
ncp-web: Implement foundation for different server push message types
Feb 16, 2019
8d62991
library.sh: Fix tmux logs not being appended to ncp.log
Feb 17, 2019
5664109
Move ncp-web refactoring to separate branch
Feb 17, 2019
4fd441d
ncp-web: Check if any app is running and attach if that is the case
Feb 17, 2019
bff0bc1
Remove vscode config from .gitignore
theCalcaholic Feb 19, 2019
2a4ee28
library.sh: Remove commented code
theCalcaholic Feb 19, 2019
cd8451d
ncp-web: Remove debug output and unnecessary variable declarations
theCalcaholic Feb 19, 2019
6c8e95c
library.sh: A number of fixes suggested in Github review
theCalcaholic Feb 19, 2019
467dc01
Move lock file to /run/ncp.lock
theCalcaholic Feb 19, 2019
59fe7ce
library.sh: Fix erroneously unescaped quotes
theCalcaholic Feb 19, 2019
a357f2c
update.sh: Create log dir and updated ncp-launcher.sh
theCalcaholic Feb 19, 2019
a0b9b28
library.sh: Restructure run_app_unsafe()
theCalcaholic Feb 19, 2019
aaa4202
ncp-launcher.sh: Remove unused aguments
theCalcaholic Feb 22, 2019
e2edadf
ncp.sh,update.sh: Improve installation of tmux, locale and new log di…
theCalcaholic Feb 22, 2019
5da8938
library.sh: Give more relevant messages depending on whether an app i…
theCalcaholic Feb 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ ncp-web/wizard.cfg
ncp-web/ncp-web.cfg
docker-armhf/qemu-arm-static
.vagrant/
.vscode/
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
179 changes: 144 additions & 35 deletions etc/library.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

CFGDIR=/usr/local/etc/ncp-config.d
BINDIR=/usr/local/bin/ncp
LOCK_FILE=/usr/local/etc/ncp.lock

function configure_app()
{
Expand All @@ -22,14 +23,16 @@ function configure_app()
type dialog &>/dev/null || { echo "please, install dialog for interactive configuration"; return 1; }
[[ -f "$cfg_file" ]] || return 0;

local cfg="$( cat "$cfg_file" )"
local len="$(jq '.params | length' <<<"$cfg")"
local cfg len
cfg="$( cat "$cfg_file" )"
len="$(jq '.params | length' <<<"$cfg")"
[[ $len -eq 0 ]] && return

# read cfg parameters
for (( i = 0 ; i < len ; i++ )); do
local var="$(jq -r ".params[$i].id" <<<"$cfg")"
local val="$(jq -r ".params[$i].value" <<<"$cfg")"
local var val
var="$(jq -r ".params[$i].id" <<<"$cfg")"
val="$(jq -r ".params[$i].value" <<<"$cfg")"
local vars+=("$var")
local vals+=("$val")
local idx=$((i+1))
Expand Down Expand Up @@ -91,8 +94,9 @@ function configure_app()

function run_app()
{
local ncp_app=$1
local script="$(find "$BINDIR" -name $ncp_app.sh)"
local script ncp_app
ncp_app=$1
script="$(find "$BINDIR" -name "$ncp_app.sh")"

[[ -f "$script" ]] || { echo "file $script not found"; return 1; }

Expand All @@ -102,10 +106,11 @@ function run_app()
# receives a script file, no security checks
function run_app_unsafe()
{
local script=$1
local ncp_app="$(basename "$script" .sh)"
local script ncp_app
script=$1
ncp_app="$(basename "$script" .sh)"
local cfg_file="$CFGDIR/$ncp_app.cfg"
local log=/var/log/ncp.log
local log=/var/log/ncp/ncp.log

[[ -f "$script" ]] || { echo "file $script not found"; return 1; }

Expand All @@ -114,51 +119,151 @@ function run_app_unsafe()
chown root:www-data $log

echo "Running $ncp_app"
echo "[ $ncp_app ]" >> $log

# read script
unset configure
source "$script"

# read cfg parameters
[[ -f "$cfg_file" ]] && {
local cfg="$( cat "$cfg_file" )"
local len="$(jq '.params | length' <<<"$cfg")"
for (( i = 0 ; i < len ; i++ )); do
local var="$(jq -r ".params[$i].id" <<<"$cfg")"
local val="$(jq -r ".params[$i].value" <<<"$cfg")"
eval "$var=$val"
done
# Check if app is already running in tmux
running_app=$( [[ -f "$LOCK_FILE" ]] && cat "$LOCK_FILE" || echo "" )
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
[[ ! -z $running_app ]] && which tmux > /dev/null && tmux has-session -t="$running_app" > /dev/null 2>&1 && {
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
#echo "Already running. Attaching to output..." | tee -a $log
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved

local choice
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
[[ $ATTACH_TO_RUNNING == "1" ]] && choice="y"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[[ $ATTACH_TO_RUNNING == "1" ]] && choice="y"
[[ "$ATTACH_TO_RUNNING" == "1" ]] && choice="y"

Copy link
Collaborator Author

@theCalcaholic theCalcaholic Feb 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My IDE tells me, that it's not required to quote variables inside double brackets?
It actually shows a warning whenever I do enclose them...

[[ $ATTACH_TO_RUNNING == "0" ]] && choice="n"
question="An app ($running_app) is already running. Do you want to attach to it's output? <y/n>"
if [[ $choice == "y" ]] || [[ $choice == "n" ]]
then
echo "$question"
echo "Choice: <y>"
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
else
read -rp "$question" choice
while [[ "$choice" != "y" ]] && [[ "$choice" != "n" ]]
do
echo "choice was '$choice'"
read -rp "Invalid choice. y or n expected." choice
done
fi

if [[ "$choice" == "y" ]]
then
attach_to_app "$running_app"
fi
return $?
}

# run
configure 2>&1 | tee -a $log
local ret="${PIPESTATUS[0]}"

unset configure
(
# read cfg parameters
[[ -f "$cfg_file" ]] && {
local len cfg
cfg="$( cat "$cfg_file" )"
jq -e '.tmux' <<<"$cfg" > /dev/null 2>&1
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
use_tmux="$?"
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
len="$(jq '.params | length' <<<"$cfg")"
for (( i = 0 ; i < len ; i++ )); do
local var val
var="$(jq -r ".params[$i].id" <<<"$cfg")"
val="$(jq -r ".params[$i].value" <<<"$cfg")"
eval "export $var=$val"
done
}

echo "$ncp_app" > "$LOCK_FILE"
if which tmux > /dev/null && [[ $use_tmux == 0 ]]
then
echo "Running $ncp_app in tmux..." | tee -a $log
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
# Run app in tmux
local tmux_log_file tmux_status_file LIBPATH
tmux_log_file="/var/log/ncp/tmux.${ncp_app}.log"
tmux_status_file="/var/log/ncp/tmux.${ncp_app}.status"
LIBPATH="$(dirname $CFGDIR)/library.sh"
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved

# Reset tmux output
echo "[ $ncp_app ]" | tee -a $log
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
echo "[ $ncp_app ]" > "$tmux_log_file"
echo "" > "$tmux_status_file"
nachoparker marked this conversation as resolved.
Show resolved Hide resolved
chmod 640 "$tmux_log_file" "$tmux_status_file"
chown root:www-data "$tmux_log_file" "$tmux_status_file"

tmux new-session -d -s "$ncp_app" "bash -c '(
trap \"echo \\\$? > $tmux_status_file && rm $LOCK_FILE\" 1 2 3 4 6 9 11 15 19 29
source \"$LIBPATH\"
source \"$script\"
configure 2>&1 | tee -a $log
echo \"\${PIPESTATUS[0]}\" > $tmux_status_file
rm $LOCK_FILE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you could add EXIT to the trap and save this, not a big deal

Copy link
Collaborator Author

@theCalcaholic theCalcaholic Feb 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about this. In the trap I write $? to the status file, not the $PIPESTATUS[0] - do you suggest to do it conditionally based on the exit code?

)' 2>&1 | tee -a $tmux_log_file"

attach_to_app "$ncp_app"
exit

else
trap "rm '$LOCK_FILE'" 0 1 2 3 4 6 11 15 19 29
echo "[ $ncp_app ]" | tee -a $log
echo "Running $ncp_app directly..." | tee -a $log
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
echo "Running $ncp_app directly..." | tee -a $log

Copy link
Collaborator Author

@theCalcaholic theCalcaholic Feb 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm... Maybe I should include a note that the user shouldn't disconnect instead? And the contrary when running in tmux?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworked in 5da8938

# read script
# shellcheck source=/dev/null
source "$script"
# run
configure 2>&1 | tee -a $log
local ret="${PIPESTATUS[0]}"
exit "$ret"
fi
)
ret="$?"
echo "" >> $log

return "$ret"
}

function attach_to_app()
{
local tmux_log_file tmux_status_file
tmux_log_file="/var/log/ncp/tmux.${ncp_app}.log"
tmux_status_file="/var/log/ncp/tmux.${ncp_app}.status"

if [[ "$ATTACH_NO_FOLLOW" == "1" ]]
then
cat "$tmux_log_file"
return 0
else
(while tmux has-session -t="$ncp_app" > /dev/null 2>&1
do
sleep 1
done) &

# Follow log file until tmux session has terminated
tail --lines=+0 -f "$tmux_log_file" --pid="$!"
fi

# Read return value from tmux log file
ret="$(tail -n 1 "$tmux_status_file")"
#rm "$tmux_log_file"
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
#rm "$tmux_status_file"

[[ $ret =~ ^[0-9]+$ ]] && return $ret
return 1
}

function is_active_app()
{
local ncp_app=$1
local bin_dir=${2:-.}
local script="$bin_dir/$ncp_app.sh"
local cfg_file="$CFGDIR/$ncp_app.cfg"

[[ -f "$script" ]] || local script="$(find "$BINDIR" -name $ncp_app.sh)"
[[ -f "$script" ]] || script="$(find "$BINDIR" -name $ncp_app.sh)"
[[ -f "$script" ]] || { echo "file $script not found"; return 1; }

# function
unset is_active
# shellcheck source=/dev/null
nachoparker marked this conversation as resolved.
Show resolved Hide resolved
source "$script"
[[ $( type -t is_active ) == function ]] && { is_active; return $?; }

# config
[[ -f "$cfg_file" ]] || return 1

local cfg="$( cat "$cfg_file" )"
local cfg
cfg="$( cat "$cfg_file" )"
[[ "$(jq -r ".params[0].id" <<<"$cfg")" == "ACTIVE" ]] && \
[[ "$(jq -r ".params[0].value" <<<"$cfg")" == "yes" ]] && \
return 0
Expand All @@ -170,9 +275,10 @@ function info_app()
local ncp_app=$1
local cfg_file="$CFGDIR/$ncp_app.cfg"

local cfg="$( cat "$cfg_file" 2>/dev/null )"
local info=$( jq -r .info <<<"$cfg" )
local infotitle=$( jq -r .infotitle <<<"$cfg" )
local cfg info infotitle
cfg="$( cat "$cfg_file" 2>/dev/null )"
info=$( jq -r .info <<<"$cfg" )
infotitle=$( jq -r .infotitle <<<"$cfg" )

[[ "$info" == "" ]] || [[ "$info" == "null" ]] && return 0
[[ "$infotitle" == "" ]] || [[ "$infotitle" == "null" ]] && infotitle="Info"
Expand All @@ -187,18 +293,20 @@ function info_app()

function install_app()
{
local script
local ncp_app=$1

# $1 can be either an installed app name or an app script
if [[ -f "$ncp_app" ]]; then
local script="$ncp_app"
local ncp_app="$(basename "$script" .sh)"
script="$ncp_app"
ncp_app="$(basename "$script" .sh)"
else
local script="$(find "$BINDIR" -name $ncp_app.sh)"
script="$(find "$BINDIR" -name $ncp_app.sh)"
fi

# do it
unset install
# shellcheck source=/dev/null
source "$script"
echo "Installing $ncp_app"
(install)
Expand All @@ -208,6 +316,7 @@ function cleanup_script()
{
local script=$1
unset cleanup
# shellcheck source=/dev/null
source "$script"
if [[ $( type -t cleanup ) == function ]]; then
cleanup
Expand Down
28 changes: 22 additions & 6 deletions ncp-web/js/ncp.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ window.onpopstate = function(event) {
click_app($('#' + selectedID));
};

function errorMsg()
{
function errorMsg(e)
{
console.log(e);
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
$('#config-box').fill( "Something went wrong. Try refreshing the page" );
}

Expand Down Expand Up @@ -268,21 +269,36 @@ $(function()
var ret = $.parseJSON( result );
if ( ret.token )
$('#csrf-token').set( { value: ret.token } );
if ( ret.ret ) // means that the process was launched
if ( "ret" in ret ) // means that the process was launched
{
if ( ret.ret == '0' )
if ( ret.ret == 0 )
{
if( ret.ref && ret.ref == 'nc-update' )
window.location.reload( true );
reload_sidebar();
$('.circle-retstatus').set('+icon-green-circle');
}
else
else if ( ret.ret == -1 )
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
{
if( ret.output )
{
var box_l = $('#' + selectedID + '-details-box');
var box = box_l[0];
var lines = ret.output.split("\n");
lines.forEach(line => {
box_l.ht( box.innerHTML + escapeHTML(line) + '<br>' );
});
box.scrollTop = box.scrollHeight;
}
$('.circle-retstatus').set('-icon-green-circle');
}
else
{
$('.circle-retstatus').set('-icon-green-circle');
}
}
else // print error from server instead
{
$('.details-box').fill(ret.output);
$('.circle-retstatus').set('-icon-green-circle');
}
$( 'input' , '#config-box-wrapper' ).set('@disabled', null);
Expand Down
32 changes: 26 additions & 6 deletions ncp-web/ncp-launcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,33 @@
}

// launch
echo '{ "token": "' . getCSRFToken() . '",'; // Get new token
echo ' "ref": "' . $ncp_app . '",';
echo ' "output": "" , ';
echo ' "ret": ';

exec( 'bash -c "sudo /home/www/ncp-launcher.sh ' . $ncp_app . '"' , $output , $ret );
echo '"' . $ret . '" }';
$ret = null;
$output = null;
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
if( file_exists("/usr/local/etc/ncp.lock") )
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
{
$running = trim(file_get_contents("/usr/local/etc/ncp.lock"));
$output = "";
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
$output .= "An app ($running) is already running...".PHP_EOL;
if ( file_exists("/var/log/ncp/tmux.$running.log") )
{
$output .= "Attaching to its output:".PHP_EOL;
$output .= file_get_contents("/var/log/ncp/tmux.$running.log");
}
$ret=-1;
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
exec( 'sudo /home/www/ncp-launcher.sh ' . $ncp_app , $output , $ret );
$output = "";
theCalcaholic marked this conversation as resolved.
Show resolved Hide resolved
}

echo json_encode(array(
"token" => getCSRFToken(),
"ref" => $ncp_app,
"output" => $output,
"ret" => $ret
));
}

//
Expand Down
2 changes: 1 addition & 1 deletion ncp-web/ncp-output.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ function follow($file)
session_write_close();
echo str_pad('',1024*1024*4); // make sure the browser buffer becomes full

$ncp_log = '/var/log/ncp.log';
$ncp_log = '/var/log/ncp/ncp.log';
if (!file_exists($ncp_log))
touch($ncp_log);
follow($ncp_log);
Expand Down
Loading