Docker runtime in progress
work in progress container manager script runtime image with autostart
frdel committed
Nov 14, 2024 at 20:27 UTC
7fc17b39c52b1a1036c8242a2f3fdbdc6ff3f741
9 files changed
+272
-21
docker/docker_manager_macos.sh
new
+137
@@ -0,0 +1,137 @@
1
+#!/bin/bash
2
+
3
+# Constants
4
+IMAGE_NAME="agent-zero-run"
5
+DEFAULT_CONTAINER_NAME="agent-zero"
6
+BASE_PORT=50080
7
+
8
+# Global variable for container IDs
9
+container_ids=()
10
+
11
+# Function to list unique containers based on the specified image
12
+list_containers() {
13
+ echo
14
+ echo "Listing all containers using image '$IMAGE_NAME':"
15
+ container_ids=() # Reset global array for each list update
16
+ container_list=$(docker ps -a --filter "ancestor=$IMAGE_NAME" --format "{{.ID}} {{.Names}} {{.Ports}}" | sort -u -k2,2)
17
+
18
+ if [ -z "$container_list" ]; then
19
+ echo "No containers found for image '$IMAGE_NAME'."
20
+ return 1
21
+ fi
22
+
23
+ index=1
24
+ printed_ids=()
25
+ while IFS= read -r line; do
26
+ container_id=$(echo "$line" | awk '{print $1}')
27
+ container_name=$(echo "$line" | awk '{print $2}')
28
+ ports=$(echo "$line" | awk '{print substr($0, index($0,$3))}')
29
+
30
+ # Extract the mapped port using sed
31
+ mapped_port=$(echo "$ports" | sed -n 's/.*0.0.0.0:\([0-9]*\)->80.*/\1/p')
32
+ container_url="http://localhost:${mapped_port}"
33
+
34
+ # Check if this ID has already been printed and mapped_port is valid
35
+ if [[ ! " ${printed_ids[@]} " =~ " ${container_id} " ]] && [ -n "$mapped_port" ]; then
36
+ printed_ids+=("$container_id")
37
+ container_ids+=("$container_id") # Store container ID in global array
38
+ printf "%2d. [%s] %s - URL: %s\n" "$index" "$container_id" "$container_name" "$container_url"
39
+ index=$((index + 1))
40
+ fi
41
+ done <<< "$container_list"
42
+ return 0
43
+}
44
+
45
+
46
+
47
+# Function to select an action for an existing container
48
+manage_container() {
49
+ container_id=$1
50
+ while true; do
51
+ echo -e "\nSelect an action for container ID: $container_id"
52
+ echo "1. Restart"
53
+ echo "2. Remove"
54
+ echo "3. View Logs"
55
+ echo "0. Back"
56
+ read -p "Choose an action (0-3): " action
57
+ case $action in
58
+ 1)
59
+ docker restart "$container_id"
60
+ echo "Container restarted."
61
+ ;;
62
+ 2)
63
+ docker rm -f "$container_id"
64
+ echo "Container removed."
65
+ return # Go back to the list screen after removing
66
+ ;;
67
+ 3)
68
+ echo -e "\n--- Logs for container ID: $container_id ---"
69
+ docker logs "$container_id"
70
+ echo -e "\n--- End of logs ---"
71
+ ;;
72
+ 0)
73
+ return
74
+ ;;
75
+ *)
76
+ echo "Invalid selection. Please choose 0, 1, 2, or 3."
77
+ ;;
78
+ esac
79
+ done
80
+}
81
+
82
+# Function to create a new container
83
+create_container() {
84
+ # Generate the default container name
85
+ container_count=$(docker ps -a --filter "name=$DEFAULT_CONTAINER_NAME" --format "{{.Names}}" | wc -l)
86
+ default_name="$DEFAULT_CONTAINER_NAME-$(($container_count + 1))"
87
+
88
+ # Prompt for the container name
89
+ read -p "Enter container name or leave empty for '$default_name': " name
90
+ name=${name:-"$default_name"}
91
+
92
+ # Calculate default port based on the container count
93
+ default_port=$((BASE_PORT + container_count + 1))
94
+ read -p "Enter web port or leave empty for '$default_port': " web_port
95
+ web_port=${web_port:-$default_port}
96
+
97
+ # Prompt for the data folder
98
+ read -p "Enter data folder or leave empty for '$(pwd)/agent-zero': " data_folder
99
+ data_folder=${data_folder:-$(pwd)/agent-zero}
100
+
101
+ # Run the container with the specified name, port mapping, and data folder
102
+ container_id=$(docker run -d -p "$web_port:80" --name "$name" -v "$data_folder:/a0" "$IMAGE_NAME:latest")
103
+ echo -e "\nContainer '$name' created with ID '$container_id', data folder '$data_folder', and web port '$web_port' mapped to port 80."
104
+}
105
+
106
+# Main program loop
107
+echo -e "\nWelcome to Agent Zero Docker Management Script.\n"
108
+while true; do
109
+ list_containers
110
+ if [ $? -ne 0 ]; then
111
+ echo -e "\nNo containers available. Would you like to create a new one? (y/n)"
112
+ read -p "> " create_new
113
+ if [ "$create_new" == "y" ]; then
114
+ create_container
115
+ else
116
+ exit 0
117
+ fi
118
+ else
119
+ echo -e "\nChoose a container by line number, type 'n' to create a new one, or 'r' to refresh the list:"
120
+ read -p "> " choice
121
+
122
+ # Refresh the list if the user inputs 'r'
123
+ if [ "$choice" == "r" ]; then
124
+ continue
125
+ fi
126
+
127
+ # Match choice to the actual container list
128
+ if [[ $choice =~ ^[0-9]+$ ]] && ((choice >= 1 && choice <= ${#container_ids[@]})); then
129
+ selected_container_id="${container_ids[$((choice - 1))]}"
130
+ manage_container "$selected_container_id"
131
+ elif [ "$choice" == "n" ]; then
132
+ create_container
133
+ else
134
+ echo "Invalid choice, please enter a valid line number, 'n' to create a new container, or 'r' to refresh the list."
135
+ fi
136
+ fi
137
+done
docker/run/Dockerfile
+22
-7
@@ -13,8 +13,15 @@ RUN apt-get update && apt-get install -y \
13
npm \
14
openssh-server \
15
sudo \
16
- git \
17
- && rm -rf /var/lib/apt/lists/*
16
+ curl \
17
+ wget \
18
+ git
19
+
20
+# Cleanup package list
21
+RUN rm -rf /var/lib/apt/lists/*
22
+
23
+# Clone Agent Zero repository
24
+RUN git clone --branch development https://github.com/frdel/agent-zero.git /git/agent-zero
25
26
# Set up SSH
27
RUN mkdir /var/run/sshd && \
@@ -25,18 +32,26 @@ RUN mkdir /var/run/sshd && \
32
ENV VIRTUAL_ENV=/opt/venv
33
RUN python3 -m venv $VIRTUAL_ENV
34
28
-# Copy initial .bashrc with virtual environment activation to a temporary location
29
-COPY .bashrc /etc/skel/.bashrc
30
-
35
# Copy the script to ensure .bashrc is in the root directory
36
COPY initialize.sh /usr/local/bin/initialize.sh
37
RUN chmod +x /usr/local/bin/initialize.sh
38
39
+# Copy contents of filesystem directory to /fs
40
+COPY ./fs/ /fs
41
+
42
# Ensure the virtual environment and pip setup
43
RUN $VIRTUAL_ENV/bin/pip install --upgrade pip
44
38
-# Expose SSH port
39
-EXPOSE 22
45
+# Install additional python packages
46
+RUN $VIRTUAL_ENV/bin/pip install \
47
+ ipython \
48
+ requests
49
+
50
+# Install A0 python packages
51
+RUN $VIRTUAL_ENV/bin/pip install -r /git/agent-zero/requirements.txt
52
+
53
+# Expose ports
54
+EXPOSE 22 80
55
56
# Init .bashrc
57
CMD ["/usr/local/bin/initialize.sh"]
\ No newline at end of file
docker/run/build.txt
+5
@@ -1 +1,6 @@
1
+# local image
2
+docker build -t agent-zero-run:latest .
3
+
4
+# dockerhub
5
+docker login
6
docker buildx build --platform linux/amd64,linux/arm64 -t frdel/agent-zero-exe:latest --push .
\ No newline at end of file
docker/run/fs/exe/node_eval.js
new
+41
@@ -0,0 +1,41 @@
1
+#!/usr/bin/env node
2
+
3
+const vm = require('vm');
4
+const path = require('path');
5
+
6
+// Create a comprehensive context with all important global objects
7
+const context = vm.createContext({
8
+ ...global,
9
+ require: require,
10
+ __filename: path.join(process.cwd(), 'eval.js'),
11
+ __dirname: process.cwd(),
12
+ module: { exports: {} },
13
+ exports: module.exports,
14
+ console: console,
15
+ process: process,
16
+ Buffer: Buffer,
17
+ setTimeout: setTimeout,
18
+ setInterval: setInterval,
19
+ setImmediate: setImmediate,
20
+ clearTimeout: clearTimeout,
21
+ clearInterval: clearInterval,
22
+ clearImmediate: clearImmediate
23
+});
24
+
25
+const code = process.argv[2];
26
+const wrappedCode = `
27
+ (async function() {
28
+ try {
29
+ const __result__ = await eval(${JSON.stringify(code)});
30
+ if (__result__ !== undefined) console.log('Out[1]:', __result__);
31
+ } catch (error) {
32
+ console.error(error);
33
+ }
34
+ })();
35
+`;
36
+
37
+vm.runInContext(wrappedCode, context, {
38
+ filename: 'eval.js',
39
+ lineOffset: -2,
40
+ columnOffset: 0,
41
+}).catch(console.error);
\ No newline at end of file
docker/run/fs/exe/run_A0.sh
new
+40
@@ -0,0 +1,40 @@
1
+#!/bin/bash
2
+
3
+# Paths
4
+PYTHON_SCRIPT="/a0/run_ui.py"
5
+SOURCE_DIR="/git/agent-zero"
6
+TARGET_DIR="/a0"
7
+
8
+
9
+# Loop to restart the Python script when it finishes
10
+while true; do
11
+
12
+ # Create virtual environment if it doesn't exist
13
+ if [ ! -d /opt/venv ]; then
14
+ echo "Creating virtual environment..."
15
+ python3 -m venv /opt/venv
16
+ /opt/venv/bin/pip install ipython requests
17
+ fi
18
+
19
+ # Activate the virtual environment
20
+ source /opt/venv/bin/activate
21
+
22
+ # Copy repository files if target is empty
23
+ if [ -z "$(ls -A "$TARGET_DIR")" ]; then
24
+ echo "Copying files from $SOURCE_DIR to $TARGET_DIR..."
25
+ cp -rn --no-preserve=ownership,mode "$SOURCE_DIR/" "$TARGET_DIR"
26
+ fi
27
+
28
+ echo "Starting A0..."
29
+ python "$PYTHON_SCRIPT" --port 80
30
+
31
+ # Check the exit status
32
+ if [ $? -ne 0 ]; then
33
+ echo "A0 script exited with an error. Restarting..."
34
+ else
35
+ echo "A0 script finished. Restarting..."
36
+ fi
37
+
38
+ # Optional: Add a small delay if needed to avoid rapid restarts
39
+ sleep 1
40
+done
docker/run/fs/root/.bashrc
renamed
docker/run/fs/root/.profile
new
+9
@@ -0,0 +1,9 @@
1
+# .bashrc
2
+
3
+# Source global definitions
4
+if [ -f /etc/bashrc ]; then
5
+ . /etc/bashrc
6
+fi
7
+
8
+# Activate the virtual environment
9
+source /opt/venv/bin/activate
docker/run/initialize.sh
+10
-11
@@ -1,18 +1,17 @@
1
#!/bin/bash
2
3
-# Ensure .bashrc is in the root directory
4
-if [ ! -f /root/.bashrc ]; then
5
- cp /etc/skel/.bashrc /root/.bashrc
6
- chmod 444 /root/.bashrc
7
-fi
3
+# Copy all contents from /fs to root directory (/) without overwriting
4
+cp -rn --no-preserve=ownership,mode /fs/* /
5
9
-# Ensure .profile is in the root directory
10
-if [ ! -f /root/.profile ]; then
11
- cp /etc/skel/.bashrc /root/.profile
12
- chmod 444 /root/.profile
13
-fi
6
+# allow execution of /root/.bashrc and /root/.profile
7
+chmod 444 /root/.bashrc
8
+chmod 444 /root/.profile
9
10
+# update package list to save time later
11
apt-get update
12
13
+# Start A0
14
+bash /exe/run_A0.sh
15
+
16
# Start SSH service
18
-exec /usr/sbin/sshd -D
17
+exec /usr/sbin/sshd -D
\ No newline at end of file
run_ui.py
+8
-3
@@ -1,3 +1,4 @@
1
+import argparse
2
import json
3
from functools import wraps
4
import os
@@ -235,13 +236,13 @@ async def handle_message(sync: bool):
236
attachments = request.files.getlist('attachments')
237
attachment_paths = []
238
238
- upload_folder = os.path.join(os.getcwd(), 'work_dir', 'uploads')
239
+ upload_folder = files.get_abs_path('work_dir/uploads')
240
241
if attachments:
242
os.makedirs(upload_folder, exist_ok=True)
243
for attachment in attachments:
244
filename = secure_filename(attachment.filename)
244
- save_path = os.path.join(upload_folder, filename)
245
+ save_path = files.get_abs_path(upload_folder, filename)
246
attachment.save(save_path)
247
attachment_paths.append(save_path)
248
else:
@@ -570,8 +571,12 @@ def run():
571
def log_request(self, code="-", size="-"):
572
pass # Override to suppress request logging
573
574
+ parser = argparse.ArgumentParser()
575
+ parser.add_argument("--port", type=int, default=0, help="Web UI port")
576
+ args = parser.parse_args()
577
+
578
# Get configuration from environment
574
- port = int(os.environ.get("WEB_UI_PORT", 0)) or None
579
+ port = args.port or int(os.environ.get("WEB_UI_PORT", 0)) or None
580
host = os.environ.get("WEB_UI_HOST") or None
581
use_cloudflare = os.environ.get("USE_CLOUDFLARE", "false").lower() == "true"
582