Skip to content

Commit

Permalink
Make it possible to run custom commands that run inside the container…
Browse files Browse the repository at this point in the history
… as a specified user inside of this container.
  • Loading branch information
lukasz-zaroda committed Mar 22, 2024
1 parent 2e01a81 commit 814a6cb
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 15 deletions.
8 changes: 3 additions & 5 deletions core/dk/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,16 @@ def display_help(arguments=None):
custom_command = custom_commands_provider.get_command(sys.argv[1])
command_file = custom_command.cmd
service = custom_command.service
custom_command_name = custom_command.name

# All reminder arguments, no matter if flags or not.
reminder_args = sys.argv[2:]
variables = config_manager.get_vars()
if service is None:
command = [command_file] + reminder_args
if custom_command.service is None:
command = [custom_command.cmd] + reminder_args
process_executor.execute(command, variables=variables)
else:
process_executor.execute_inside_container(
service,
command_file,
custom_command,
reminder_args,
variables
)
4 changes: 2 additions & 2 deletions core/dk/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class Flag:
help: str
action: str = field(default_factory=lambda: 'store')


@dataclass(kw_only=True)
class EmptyCommand:
"""Dataclass representing command without any callback.
Expand All @@ -22,18 +23,17 @@ class EmptyCommand:
flags: list[Flag] = field(default_factory=lambda: [])



@dataclass(kw_only=True)
class CallableCommand(EmptyCommand):
"""Dataclass representing a command.
"""
callback: Callable[[list], None]|None



@dataclass(kw_only=True)
class ServiceCommand(EmptyCommand):
"""Dataclass representing a service command.
"""
service: str
cmd: str
user: str = '0'
8 changes: 6 additions & 2 deletions core/dk/custom_commands_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,14 @@ def __gather_custom_commands(self) -> list[ServiceCommand]:

# Find yaml companion.
help_text = ''
user: str = '0'
try:
with open(full_path + ".yml", "r", encoding='utf8') as stream:
yaml_companion = yaml.safe_load(stream)
help_text = yaml_companion['help']\
if yaml_companion and 'help' in yaml_companion else ''
if 'help' in yaml_companion:
help_text = str(yaml_companion['help'])
if 'user' in yaml_companion:
user = str(yaml_companion['user'])
except (IOError, yaml.YAMLError):
pass

Expand All @@ -75,6 +78,7 @@ def __gather_custom_commands(self) -> list[ServiceCommand]:
help=help_text,
service=service,
cmd=full_path,
user=user
)
)

Expand Down
11 changes: 6 additions & 5 deletions core/dk/process_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import yaml

from dk.command import ServiceCommand
from dk.compose_manager import ComposeManager, ComposeRecipe
from dk.config_manager import ConfigManager
from dk.hook_manager import HookManager
Expand Down Expand Up @@ -137,19 +138,19 @@ def execute_pipe(

def execute_inside_container(
self,
service: str,
script_path: str,
custom_command: ServiceCommand,
reminder_args: list,
variables=None
) -> None:
"""Executes given script in a given service's container.
:param variables:
:param service:
:param script_path:
:param custom_command:
:param reminder_args:
:return:
"""
service = custom_command.service
script_path = custom_command.cmd
script_path_with_draky_root = get_path_up_to_project_root(script_path)
if variables is None:
variables = {}
Expand All @@ -171,7 +172,7 @@ def execute_inside_container(

# Run the script by using docker's "exec" command.
command = self.get_command_base()
command.extend(['exec'])
command.extend(['exec', '-u', custom_command.user])

# Pass the variables to the container running the command.
for var in variables:
Expand Down
63 changes: 62 additions & 1 deletion tests/functional/tests.bats
Original file line number Diff line number Diff line change
Expand Up @@ -515,4 +515,65 @@ EOF
run bash -c "echo \"${TEST_SERVICE_COMMAND_STDIN_DATA}\" | ${DRAKY} ${TEST_SERVICE_COMMAND_NAME}"
[[ "$output" == *"${TEST_SERVICE_COMMAND_MESSAGE}"* ]]
[[ "$output" == *"${TEST_SERVICE_COMMAND_STDIN_DATA}"* ]]
}
}

@test "Custom commands: command is run inside the container as a specified user by id" {
_initialize_test_environment
TEST_SERVICE=test_service
USER_ID=1100
# Create the compose file.
cat > "$COMPOSE_PATH" << EOF
services:
$TEST_SERVICE:
image: ghcr.io/draky-dev/draky-generic-testing-environment:1.0.0
command: 'tail -f /dev/null'
EOF
TEST_COMMAND_NAME="testcommand"
TEST_COMMAND_PATH="${TEST_PROJECT_PATH}/.draky/$TEST_COMMAND_NAME.$TEST_SERVICE.dk.sh"
TEST_COMMAND_COMPANION_PATH="${TEST_COMMAND_PATH}.yml"

cat > "${TEST_COMMAND_PATH}" << EOF
#!/usr/bin/env sh
id -u
EOF
chmod a+x "${TEST_COMMAND_PATH}"

cat > "${TEST_COMMAND_COMPANION_PATH}" << EOF
user: ${USER_ID}
EOF

${DRAKY} env up
run "${DRAKY}" "${TEST_COMMAND_NAME}"
[[ "$output" == *"${USER_ID}"* ]]
}

@test "Custom commands: command is run inside the container as a specified user by name" {
_initialize_test_environment
TEST_SERVICE=test_service
USER=bin
# Create the compose file.
cat > "$COMPOSE_PATH" << EOF
services:
$TEST_SERVICE:
image: ghcr.io/draky-dev/draky-generic-testing-environment:1.0.0
command: 'tail -f /dev/null'
EOF
TEST_COMMAND_NAME="testcommand"
TEST_COMMAND_PATH="${TEST_PROJECT_PATH}/.draky/$TEST_COMMAND_NAME.$TEST_SERVICE.dk.sh"
TEST_COMMAND_COMPANION_PATH="${TEST_COMMAND_PATH}.yml"

cat > "${TEST_COMMAND_PATH}" << EOF
#!/usr/bin/env sh
id
EOF
chmod a+x "${TEST_COMMAND_PATH}"

cat > "${TEST_COMMAND_COMPANION_PATH}" << EOF
user: ${USER}
EOF

${DRAKY} env up
run "${DRAKY}" "${TEST_COMMAND_NAME}"
echo "$output"
[[ "$output" == *"${USER}"* ]]
}

0 comments on commit 814a6cb

Please sign in to comment.