Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
epm-docker-test
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Иван Мажукин
epm-docker-test
Commits
8d9bdd72
Commit
8d9bdd72
authored
Mar 30, 2026
by
Ivan Mazhukin
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Init commit
parents
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
442 additions
and
0 deletions
+442
-0
epm-docker-test.sh
epm-docker-test.sh
+442
-0
No files found.
epm-docker-test.sh
0 → 100755
View file @
8d9bdd72
#!/usr/bin/env bash
set
-euo
pipefail
SCRIPT_NAME
=
"
$(
basename
"
$0
"
)
"
SCRIPT_PATH
=
"
$(
realpath
"
${
BASH_SOURCE
[0]
}
"
)
"
DEFAULT_REMOTE_HOST
=
"
${
EPM_DOCKER_TEST_REMOTE_HOST
:-
localhost
}
"
DEFAULT_LOG_ROOT
=
"
${
XDG_STATE_HOME
:-
$HOME
/.local/state
}
/epm-docker-test"
COMMAND
=
"play"
APP_NAME
=
""
SYSTEM_INPUT
=
""
SYSTEM_IMAGE
=
""
RUN_MODE
=
"auto"
REMOTE_HOST
=
"
$DEFAULT_REMOTE_HOST
"
REMOTE_USER
=
""
SOURCE_KIND
=
"local"
SOURCE_PATH
=
""
BUILDER_USER
=
""
BUILDER_PATH
=
""
INTERNAL_LOCAL_RUN
=
0
LOG_ROOT
=
"
$DEFAULT_LOG_ROOT
"
LOG_FILE
=
""
usage
()
{
cat
<<
'
EOF
'
Usage:
epm-docker-test.sh [options] play <app> <system>
epm-docker-test.sh [options] <app> <system>
Options:
--mode <auto|local|remote> Runner mode. Default: auto
--remote Shortcut for --mode remote
--local Shortcut for --mode local
--remote-host <host> SSH host for fallback runner. Default: localhost
--remote-user <user> SSH user with Docker access
--eepm-source <local|builder64>
eepm source selector. Default: local
--eepm-dir <path> Explicit eepm tree path
--builder-user <user> Preferred owner for ~/Projects/... lookup
--builder-path <path> Explicit builder64 source path
--log-root <path> Directory for saved logs
-h, --help Show this help
Examples:
epm-docker-test.sh nginx fedora
epm-docker-test.sh play nginx Fedora/43
epm-docker-test.sh --remote-user dockerbot --eepm-source builder64 nginx fedora:43
EOF
}
info
()
{
printf
'[info] %s\n'
"
$*
"
>
&2
}
warn
()
{
printf
'[warn] %s\n'
"
$*
"
>
&2
}
fatal
()
{
printf
'[error] %s\n'
"
$*
"
>
&2
exit
1
}
require_command
()
{
local
cmd
=
"
$1
"
command
-v
"
$cmd
"
>
/dev/null 2>&1
||
fatal
"Required command not found:
$cmd
"
}
slugify
()
{
local
value
=
"
${
1
,,
}
"
value
=
"
${
value
//[^a-z0-9]/-
}
"
value
=
"
${
value
##-
}
"
value
=
"
${
value
%%-
}
"
printf
'%s\n'
"
${
value
:-
run
}
"
}
normalize_system_name
()
{
local
raw
=
"
$1
"
local
normalized
normalized
=
"
${
raw
// /
}
"
normalized
=
"
${
normalized
,,
}
"
normalized
=
"
${
normalized
//\//
:
}
"
[[
-n
"
$normalized
"
]]
||
fatal
"Target system is empty"
if
[[
"
$normalized
"
!=
*
:
*
]]
;
then
normalized
=
"
${
normalized
}
:latest"
fi
if
[[
"
$normalized
"
=
~ ^[a-z0-9._/-]+:[a-z0-9._-]+
$
]]
;
then
printf
'%s\n'
"
$normalized
"
return
0
fi
fatal
"Unsupported system format:
$raw
"
}
can_use_local_docker
()
{
command
-v
docker
>
/dev/null 2>&1
||
return
1
docker info
>
/dev/null 2>&1
}
discover_remote_user
()
{
# TODO: implement remote user discovery for docker access.
return
1
}
user_home_dir
()
{
local
user
=
"
$1
"
local
passwd_line
if
command
-v
getent
>
/dev/null 2>&1
;
then
passwd_line
=
"
$(
getent passwd
"
$user
"
||
true
)
"
if
[[
-n
"
$passwd_line
"
]]
;
then
printf
'%s\n'
"
${
passwd_line
##*
:
}
"
return
0
fi
fi
printf
'/home/%s\n'
"
$user
"
}
project_suffix_from_pwd
()
{
local
cwd marker
cwd
=
"
$(
pwd
-P
)
"
marker
=
"/Projects/"
if
[[
"
$cwd
"
==
*
"
$marker
"
*
]]
;
then
printf
'%s\n'
"
${
cwd
#*
"
$marker
"
}
"
return
0
fi
basename
"
$cwd
"
}
verify_eepm_tree
()
{
local
tree
=
"
$1
"
[[
-d
"
$tree
"
]]
||
fatal
"eepm tree is not a directory:
$tree
"
[[
-f
"
$tree
/epm"
]]
||
fatal
"eepm tree does not contain ./epm:
$tree
"
}
resolve_local_source_path
()
{
local
candidate
candidate
=
"
${
SOURCE_PATH
:-$(
pwd
-P
)}
"
candidate
=
"
$(
realpath
"
$candidate
"
)
"
verify_eepm_tree
"
$candidate
"
printf
'%s\n'
"
$candidate
"
}
resolve_builder_source_path
()
{
# TODO: implement builder64 source discovery.
fatal
"TODO: resolve_builder_source_path is not implemented yet"
}
resolve_source_path
()
{
case
"
$SOURCE_KIND
"
in
local
)
resolve_local_source_path
;;
builder64
)
resolve_builder_source_path
;;
explicit
)
[[
-n
"
$SOURCE_PATH
"
]]
||
fatal
"Explicit source path is empty"
SOURCE_PATH
=
"
$(
realpath
"
$SOURCE_PATH
"
)
"
verify_eepm_tree
"
$SOURCE_PATH
"
printf
'%s\n'
"
$SOURCE_PATH
"
;;
*
)
fatal
"Unsupported eepm source kind:
$SOURCE_KIND
"
;;
esac
}
create_log_file
()
{
local
safe_app safe_system run_dir timestamp
if
!
mkdir
-p
"
$LOG_ROOT
"
2>/dev/null
;
then
warn
"Cannot write to log root
$LOG_ROOT
; falling back to
${
TMPDIR
:-
/tmp
}
/epm-docker-test"
LOG_ROOT
=
"
${
TMPDIR
:-
/tmp
}
/epm-docker-test"
mkdir
-p
"
$LOG_ROOT
"
||
fatal
"Could not create log root:
$LOG_ROOT
"
fi
safe_app
=
"
$(
slugify
"
$APP_NAME
"
)
"
safe_system
=
"
$(
slugify
"
$SYSTEM_IMAGE
"
)
"
timestamp
=
"
$(
date
+%Y%m%d-%H%M%S
)
"
run_dir
=
"
$LOG_ROOT
/
$timestamp
-
$safe_app
-
$safe_system
"
mkdir
-p
"
$run_dir
"
||
fatal
"Could not create log directory:
$run_dir
"
printf
'%s\n'
"
$run_dir
/run.log"
}
print_failure_excerpt
()
{
local
matches
[[
-f
"
$LOG_FILE
"
]]
||
{
printf
'\nNo log file was captured.\n'
>
&2
return
0
}
printf
'\nCritical log lines:\n'
>
&2
matches
=
"
$(
grep
-nEi
'critical|fatal|error|failed|traceback|no such|permission denied'
"
$LOG_FILE
"
|
tail
-n
20
||
true
)
"
if
[[
-n
"
$matches
"
]]
;
then
printf
'%s\n'
"
$matches
"
>
&2
return
0
fi
tail
-n
40
"
$LOG_FILE
"
>
&2
||
true
}
build_container_script
()
{
local
script_path
=
"
$1
"
# TODO: generate container bootstrap/run script.
fatal
"TODO: build_container_script is not implemented yet"
}
run_container_locally
()
{
local
resolved_source
=
"
$1
"
local
inner_script container_name
require_command docker
inner_script
=
"
$(
mktemp
"
${
TMPDIR
:-
/tmp
}
/epm-docker-test-inner.XXXXXX.sh"
)
"
trap
'rm -f "$inner_script"'
RETURN
build_container_script
"
$inner_script
"
container_name
=
"epm-test-
$(
slugify
"
$APP_NAME
"
)
-
$(
slugify
"
$SYSTEM_IMAGE
"
)
-
$$
"
info
"Using eepm tree:
$resolved_source
"
info
"Target image:
$SYSTEM_IMAGE
"
info
"Runner: local docker"
docker run
--rm
\
--name
"
$container_name
"
\
--hostname
epm-docker-test
\
--workdir
/work/eepm
\
--volume
"
$resolved_source
:/work/eepm:ro"
\
--volume
"
$inner_script
:/tmp/epm-docker-test-inner.sh:ro"
\
"
$SYSTEM_IMAGE
"
\
bash /tmp/epm-docker-test-inner.sh
"
$COMMAND
"
"
$APP_NAME
"
}
build_remote_args
()
{
local
-a
args
local
explicit_local_source
args
=(
--internal-local-run
--mode
local
)
if
[[
"
$SOURCE_KIND
"
==
"local"
||
"
$SOURCE_KIND
"
==
"explicit"
]]
;
then
explicit_local_source
=
"
$(
resolve_local_source_path
)
"
args+
=(
--eepm-source
explicit
--eepm-dir
"
$explicit_local_source
"
)
else
args+
=(
--eepm-source
"
$SOURCE_KIND
"
)
[[
-n
"
$BUILDER_USER
"
]]
&&
args+
=(
--builder-user
"
$BUILDER_USER
"
)
[[
-n
"
$BUILDER_PATH
"
]]
&&
args+
=(
--builder-path
"
$BUILDER_PATH
"
)
fi
args+
=(
"
$COMMAND
"
"
$APP_NAME
"
"
$SYSTEM_IMAGE
"
)
printf
'%s\0'
"
${
args
[@]
}
"
}
run_container_via_ssh
()
{
local
target_user target
local
-a
ssh_args forwarded_args
require_command ssh
target_user
=
"
${
REMOTE_USER
:-$(
discover_remote_user
||
true
)}
"
[[
-n
"
$target_user
"
]]
||
fatal
"Could not determine remote user with Docker access; use --remote-user"
target
=
"
${
target_user
}
@
${
REMOTE_HOST
}
"
info
"Runner: ssh ->
$target
"
while
IFS
=
read
-r
-d
''
arg
;
do
forwarded_args+
=(
"
$arg
"
)
done
< <
(
build_remote_args
)
ssh_args
=(
-o
BatchMode
=
yes
-o
StrictHostKeyChecking
=
accept-new
"
$target
"
bash
-s
--
)
ssh
"
${
ssh_args
[@]
}
"
"
${
forwarded_args
[@]
}
"
<
"
$SCRIPT_PATH
"
}
run_once
()
{
local
resolved_source
case
"
$RUN_MODE
"
in
auto
)
if
can_use_local_docker
;
then
resolved_source
=
"
$(
resolve_source_path
)
"
run_container_locally
"
$resolved_source
"
else
warn
"Local Docker is unavailable; falling back to ssh runner"
run_container_via_ssh
fi
;;
local
)
resolved_source
=
"
$(
resolve_source_path
)
"
run_container_locally
"
$resolved_source
"
;;
remote
)
run_container_via_ssh
;;
*
)
fatal
"Unsupported run mode:
$RUN_MODE
"
;;
esac
}
parse_args
()
{
local
positional
=()
while
((
$#
>
0
))
;
do
case
"
$1
"
in
play
)
COMMAND
=
"play"
shift
;;
--mode
)
[[
$#
-ge
2
]]
||
fatal
"--mode requires a value"
RUN_MODE
=
"
$2
"
shift
2
;;
--remote
)
RUN_MODE
=
"remote"
shift
;;
--local
)
RUN_MODE
=
"local"
shift
;;
--remote-host
)
[[
$#
-ge
2
]]
||
fatal
"--remote-host requires a value"
REMOTE_HOST
=
"
$2
"
shift
2
;;
--remote-user
)
[[
$#
-ge
2
]]
||
fatal
"--remote-user requires a value"
REMOTE_USER
=
"
$2
"
shift
2
;;
--eepm-source
)
[[
$#
-ge
2
]]
||
fatal
"--eepm-source requires a value"
SOURCE_KIND
=
"
$2
"
shift
2
;;
--eepm-dir
)
[[
$#
-ge
2
]]
||
fatal
"--eepm-dir requires a value"
SOURCE_PATH
=
"
$2
"
shift
2
;;
--builder-user
)
[[
$#
-ge
2
]]
||
fatal
"--builder-user requires a value"
BUILDER_USER
=
"
$2
"
shift
2
;;
--builder-path
)
[[
$#
-ge
2
]]
||
fatal
"--builder-path requires a value"
BUILDER_PATH
=
"
$2
"
shift
2
;;
--log-root
)
[[
$#
-ge
2
]]
||
fatal
"--log-root requires a value"
LOG_ROOT
=
"
$2
"
shift
2
;;
--internal-local-run
)
INTERNAL_LOCAL_RUN
=
1
shift
;;
-h
|
--help
)
usage
exit
0
;;
--
)
shift
while
((
$#
>
0
))
;
do
positional+
=(
"
$1
"
)
shift
done
;;
-
*
)
fatal
"Unknown option:
$1
"
;;
*
)
positional+
=(
"
$1
"
)
shift
;;
esac
done
if
((
${#
positional
[@]
}
!=
2
))
;
then
usage
>
&2
exit
1
fi
APP_NAME
=
"
${
positional
[0]
}
"
SYSTEM_INPUT
=
"
${
positional
[1]
}
"
}
main
()
{
local
status
parse_args
"
$@
"
SYSTEM_IMAGE
=
"
$(
normalize_system_name
"
$SYSTEM_INPUT
"
)
"
if
((
INTERNAL_LOCAL_RUN
))
;
then
run_once
return
0
fi
LOG_FILE
=
"
$(
create_log_file
)
"
info
"Log file:
$LOG_FILE
"
info
"Normalized system:
$SYSTEM_IMAGE
"
info
"Test command: epm
$COMMAND
$APP_NAME
"
if
run_once 2>&1 |
tee
"
$LOG_FILE
"
;
then
status
=
0
else
status
=
$?
fi
if
((
status
==
0
))
;
then
printf
'\nTest passed: epm %s %s on %s\n'
"
$COMMAND
"
"
$APP_NAME
"
"
$SYSTEM_IMAGE
"
printf
'Log: %s\n'
"
$LOG_FILE
"
else
printf
'\nTest failed: epm %s %s on %s\n'
"
$COMMAND
"
"
$APP_NAME
"
"
$SYSTEM_IMAGE
"
>
&2
printf
'Log: %s\n'
"
$LOG_FILE
"
>
&2
print_failure_excerpt
fi
return
"
$status
"
}
main
"
$@
"
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment