ruby_llm-docker 0.0.1 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +255 -11
- data/Rakefile +3 -3
- data/examples/docker_chat.rb +228 -0
- data/examples/list_containers.rb +36 -0
- data/examples/test_chat.rb +81 -0
- data/lib/ruby_llm/docker/build_image.rb +111 -0
- data/lib/ruby_llm/docker/copy_to_container.rb +196 -0
- data/lib/ruby_llm/docker/create_container.rb +146 -0
- data/lib/ruby_llm/docker/create_network.rb +131 -0
- data/lib/ruby_llm/docker/create_volume.rb +129 -0
- data/lib/ruby_llm/docker/exec_container.rb +185 -0
- data/lib/ruby_llm/docker/fetch_container_logs.rb +132 -0
- data/lib/ruby_llm/docker/list_containers.rb +59 -0
- data/lib/ruby_llm/docker/list_images.rb +79 -0
- data/lib/ruby_llm/docker/list_networks.rb +81 -0
- data/lib/ruby_llm/docker/list_volumes.rb +88 -0
- data/lib/ruby_llm/docker/pull_image.rb +127 -0
- data/lib/ruby_llm/docker/push_image.rb +153 -0
- data/lib/ruby_llm/docker/recreate_container.rb +151 -0
- data/lib/ruby_llm/docker/remove_container.rb +120 -0
- data/lib/ruby_llm/docker/remove_image.rb +142 -0
- data/lib/ruby_llm/docker/remove_network.rb +120 -0
- data/lib/ruby_llm/docker/remove_volume.rb +127 -0
- data/lib/ruby_llm/docker/run_container.rb +104 -0
- data/lib/ruby_llm/docker/start_container.rb +97 -0
- data/lib/ruby_llm/docker/stop_container.rb +109 -0
- data/lib/ruby_llm/docker/tag_image.rb +139 -0
- data/lib/ruby_llm/docker/version.rb +2 -2
- data/lib/ruby_llm/docker.rb +53 -3
- data/sig/ruby_llm/docker.rbs +1 -1
- metadata +90 -5
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Docker
|
|
5
|
+
# RubyLLM tool for removing Docker images.
|
|
6
|
+
#
|
|
7
|
+
# This tool provides the ability to permanently delete Docker images from
|
|
8
|
+
# the local system to free up disk space and remove unused images. It
|
|
9
|
+
# supports both regular and forced removal with options for parent image
|
|
10
|
+
# handling.
|
|
11
|
+
#
|
|
12
|
+
# == Features
|
|
13
|
+
#
|
|
14
|
+
# - Remove images by ID, name, or name:tag
|
|
15
|
+
# - Force removal of images in use
|
|
16
|
+
# - Control parent image cleanup
|
|
17
|
+
# - Comprehensive error handling
|
|
18
|
+
# - Safe removal with dependency checking
|
|
19
|
+
#
|
|
20
|
+
# == ⚠️ Data Loss Warning ⚠️
|
|
21
|
+
#
|
|
22
|
+
# **DESTRUCTIVE OPERATION - PERMANENT DATA LOSS**
|
|
23
|
+
#
|
|
24
|
+
# This operation permanently deletes images and associated data:
|
|
25
|
+
# - Image layers are deleted from disk
|
|
26
|
+
# - All tags pointing to the image are removed
|
|
27
|
+
# - Operation cannot be undone
|
|
28
|
+
# - Dependent containers may become unusable
|
|
29
|
+
# - Custom modifications to images are lost
|
|
30
|
+
#
|
|
31
|
+
# == Dependency Management
|
|
32
|
+
#
|
|
33
|
+
# Docker images have complex dependency relationships:
|
|
34
|
+
# - **Child Images**: Images built FROM this image
|
|
35
|
+
# - **Parent Images**: Base images this image depends on
|
|
36
|
+
# - **Running Containers**: Containers using this image
|
|
37
|
+
# - **Stopped Containers**: Containers that could be restarted
|
|
38
|
+
#
|
|
39
|
+
# == Security Considerations
|
|
40
|
+
#
|
|
41
|
+
# Image removal affects system security posture:
|
|
42
|
+
# - Removes potentially vulnerable software
|
|
43
|
+
# - May break running applications
|
|
44
|
+
# - Could remove security patches
|
|
45
|
+
# - Affects rollback capabilities
|
|
46
|
+
#
|
|
47
|
+
# Best practices:
|
|
48
|
+
# - Verify no critical containers depend on the image
|
|
49
|
+
# - Backup important images before removal
|
|
50
|
+
# - Use force removal judiciously
|
|
51
|
+
# - Monitor disk space after removal
|
|
52
|
+
# - Maintain image inventory documentation
|
|
53
|
+
#
|
|
54
|
+
# == Removal Options
|
|
55
|
+
#
|
|
56
|
+
# - **Normal Removal**: Only removes if no containers use the image
|
|
57
|
+
# - **Force Removal**: Removes even if containers depend on it
|
|
58
|
+
# - **Prune Parents**: Automatically removes unused parent images
|
|
59
|
+
# - **No Prune**: Keeps parent images even if unused
|
|
60
|
+
#
|
|
61
|
+
# == Example Usage
|
|
62
|
+
#
|
|
63
|
+
# # Safe removal of unused image
|
|
64
|
+
# RemoveImage.call(
|
|
65
|
+
# server_context: context,
|
|
66
|
+
# id: "old-app:v1.0"
|
|
67
|
+
# )
|
|
68
|
+
#
|
|
69
|
+
# # Force removal of image in use
|
|
70
|
+
# RemoveImage.call(
|
|
71
|
+
# server_context: context,
|
|
72
|
+
# id: "broken-image:latest",
|
|
73
|
+
# force: true
|
|
74
|
+
# )
|
|
75
|
+
#
|
|
76
|
+
# # Remove image but keep parent layers
|
|
77
|
+
# RemoveImage.call(
|
|
78
|
+
# server_context: context,
|
|
79
|
+
# id: "temp-build:abc123",
|
|
80
|
+
# noprune: true
|
|
81
|
+
# )
|
|
82
|
+
#
|
|
83
|
+
# @see ListImages
|
|
84
|
+
# @see BuildImage
|
|
85
|
+
# @see Docker::Image#remove
|
|
86
|
+
# @since 0.1.0
|
|
87
|
+
class RemoveImage < RubyLLM::Tool
|
|
88
|
+
description 'Remove a Docker image'
|
|
89
|
+
|
|
90
|
+
param :id, type: :string, desc: 'Image ID, name, or name:tag'
|
|
91
|
+
param :force, type: :boolean, desc: 'Force removal of the image (default: false)', required: false
|
|
92
|
+
param :noprune, type: :boolean, desc: 'Do not delete untagged parents (default: false)', required: false
|
|
93
|
+
|
|
94
|
+
# Remove a Docker image from the local system.
|
|
95
|
+
#
|
|
96
|
+
# This method permanently deletes the specified image from local storage.
|
|
97
|
+
# By default, it performs safety checks to prevent removal of images with
|
|
98
|
+
# dependent containers. Force removal bypasses these checks.
|
|
99
|
+
#
|
|
100
|
+
# @param id [String] image ID, name, or name:tag to remove
|
|
101
|
+
# @param server_context [Object] RubyLLM context (unused but required)
|
|
102
|
+
# @param force [Boolean] whether to force removal despite dependencies (default: false)
|
|
103
|
+
# @param noprune [Boolean] whether to preserve parent images (default: false)
|
|
104
|
+
#
|
|
105
|
+
# @return [RubyLLM::Tool::Response] removal operation results
|
|
106
|
+
#
|
|
107
|
+
# @raise [Docker::Error::NotFoundError] if image doesn't exist
|
|
108
|
+
# @raise [StandardError] for removal failures or dependency conflicts
|
|
109
|
+
#
|
|
110
|
+
# @example Remove unused image
|
|
111
|
+
# response = RemoveImage.call(
|
|
112
|
+
# server_context: context,
|
|
113
|
+
# id: "old-version:1.0"
|
|
114
|
+
# )
|
|
115
|
+
#
|
|
116
|
+
# @example Force remove problematic image
|
|
117
|
+
# response = RemoveImage.call(
|
|
118
|
+
# server_context: context,
|
|
119
|
+
# id: "corrupted-image",
|
|
120
|
+
# force: true
|
|
121
|
+
# )
|
|
122
|
+
#
|
|
123
|
+
# @example Remove while preserving layers
|
|
124
|
+
# response = tool.execute(
|
|
125
|
+
# id: "temp-image:build-123",
|
|
126
|
+
# noprune: true
|
|
127
|
+
# )
|
|
128
|
+
#
|
|
129
|
+
# @see Docker::Image#remove
|
|
130
|
+
def execute(id:, force: false, noprune: false)
|
|
131
|
+
image = ::Docker::Image.get(id)
|
|
132
|
+
image.remove(force: force, noprune: noprune)
|
|
133
|
+
|
|
134
|
+
"Image #{id} removed successfully"
|
|
135
|
+
rescue ::Docker::Error::NotFoundError
|
|
136
|
+
"Image #{id} not found"
|
|
137
|
+
rescue StandardError => e
|
|
138
|
+
"Error removing image: #{e.message}"
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Docker
|
|
5
|
+
# RubyLLM tool for removing Docker networks.
|
|
6
|
+
#
|
|
7
|
+
# This tool provides the ability to permanently delete Docker networks from
|
|
8
|
+
# the system. It safely removes custom networks while protecting built-in
|
|
9
|
+
# system networks from accidental deletion.
|
|
10
|
+
#
|
|
11
|
+
# == Features
|
|
12
|
+
#
|
|
13
|
+
# - Remove custom Docker networks by ID or name
|
|
14
|
+
# - Protection against removing built-in networks
|
|
15
|
+
# - Comprehensive error handling
|
|
16
|
+
# - Dependency checking (prevents removal if containers are connected)
|
|
17
|
+
# - Safe cleanup of network resources
|
|
18
|
+
#
|
|
19
|
+
# == ⚠️ Service Disruption Warning ⚠️
|
|
20
|
+
#
|
|
21
|
+
# **NETWORK REMOVAL CAN DISRUPT SERVICES**
|
|
22
|
+
#
|
|
23
|
+
# Removing networks can cause immediate service disruption:
|
|
24
|
+
# - Connected containers lose network connectivity
|
|
25
|
+
# - Inter-container communication is broken
|
|
26
|
+
# - Services may become unreachable
|
|
27
|
+
# - Application functionality can be severely impacted
|
|
28
|
+
# - Network-dependent processes may fail
|
|
29
|
+
#
|
|
30
|
+
# == Protected Networks
|
|
31
|
+
#
|
|
32
|
+
# Docker protects certain built-in networks from removal:
|
|
33
|
+
# - **bridge**: Default bridge network
|
|
34
|
+
# - **host**: Host networking
|
|
35
|
+
# - **none**: No networking
|
|
36
|
+
# - **System networks**: Docker-managed networks
|
|
37
|
+
#
|
|
38
|
+
# == Security Considerations
|
|
39
|
+
#
|
|
40
|
+
# Network removal affects security boundaries:
|
|
41
|
+
# - Removes network isolation between containers
|
|
42
|
+
# - May expose containers to unintended networks
|
|
43
|
+
# - Could impact security segmentation strategies
|
|
44
|
+
# - Affects network-based access controls
|
|
45
|
+
#
|
|
46
|
+
# Security implications:
|
|
47
|
+
# - Ensure no critical containers depend on the network
|
|
48
|
+
# - Verify alternative connectivity exists if needed
|
|
49
|
+
# - Consider impact on security boundaries
|
|
50
|
+
# - Monitor for unauthorized network modifications
|
|
51
|
+
#
|
|
52
|
+
# Best practices:
|
|
53
|
+
# - Stop containers before removing their networks
|
|
54
|
+
# - Verify network dependencies before removal
|
|
55
|
+
# - Have rollback plans for critical networks
|
|
56
|
+
# - Document network removal procedures
|
|
57
|
+
# - Monitor network connectivity after removal
|
|
58
|
+
#
|
|
59
|
+
# == Example Usage
|
|
60
|
+
#
|
|
61
|
+
# # Remove custom network
|
|
62
|
+
# RemoveNetwork.call(
|
|
63
|
+
# server_context: context,
|
|
64
|
+
# id: "app-network"
|
|
65
|
+
# )
|
|
66
|
+
#
|
|
67
|
+
# # Remove by network ID
|
|
68
|
+
# RemoveNetwork.call(
|
|
69
|
+
# server_context: context,
|
|
70
|
+
# id: "abc123def456"
|
|
71
|
+
# )
|
|
72
|
+
#
|
|
73
|
+
# @see CreateNetwork
|
|
74
|
+
# @see ListNetworks
|
|
75
|
+
# @see Docker::Network#delete
|
|
76
|
+
# @since 0.1.0
|
|
77
|
+
class RemoveNetwork < RubyLLM::Tool
|
|
78
|
+
description 'Remove a Docker network'
|
|
79
|
+
|
|
80
|
+
param :id, type: :string, desc: 'Network ID or name'
|
|
81
|
+
|
|
82
|
+
# Remove a Docker network from the system.
|
|
83
|
+
#
|
|
84
|
+
# This method permanently deletes the specified network. The network
|
|
85
|
+
# must not have any containers connected to it, and built-in system
|
|
86
|
+
# networks cannot be removed.
|
|
87
|
+
#
|
|
88
|
+
# @param id [String] network ID or name to remove
|
|
89
|
+
# @param server_context [Object] RubyLLM context (unused but required)
|
|
90
|
+
#
|
|
91
|
+
# @return [RubyLLM::Tool::Response] removal operation results
|
|
92
|
+
#
|
|
93
|
+
# @raise [Docker::Error::NotFoundError] if network doesn't exist
|
|
94
|
+
# @raise [StandardError] for removal failures or dependency conflicts
|
|
95
|
+
#
|
|
96
|
+
# @example Remove custom network
|
|
97
|
+
# response = RemoveNetwork.call(
|
|
98
|
+
# server_context: context,
|
|
99
|
+
# id: "frontend-network"
|
|
100
|
+
# )
|
|
101
|
+
#
|
|
102
|
+
# @example Remove by ID
|
|
103
|
+
# response = tool.execute(
|
|
104
|
+
# id: "1a2b3c4d5e6f"
|
|
105
|
+
# )
|
|
106
|
+
#
|
|
107
|
+
# @see Docker::Network#delete
|
|
108
|
+
def execute(id:)
|
|
109
|
+
network = ::Docker::Network.get(id)
|
|
110
|
+
network.delete
|
|
111
|
+
|
|
112
|
+
"Network #{id} removed successfully"
|
|
113
|
+
rescue ::Docker::Error::NotFoundError
|
|
114
|
+
"Network #{id} not found"
|
|
115
|
+
rescue StandardError => e
|
|
116
|
+
"Error removing network: #{e.message}"
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Docker
|
|
5
|
+
# RubyLLM tool for removing Docker volumes.
|
|
6
|
+
#
|
|
7
|
+
# This tool provides the ability to permanently delete Docker volumes from
|
|
8
|
+
# the system. This is a destructive operation that will permanently delete
|
|
9
|
+
# all data stored in the volume.
|
|
10
|
+
#
|
|
11
|
+
# == Features
|
|
12
|
+
#
|
|
13
|
+
# - Remove Docker volumes by name
|
|
14
|
+
# - Force removal option for volumes in use
|
|
15
|
+
# - Comprehensive error handling
|
|
16
|
+
# - Dependency checking (prevents removal if containers are using the volume)
|
|
17
|
+
# - Safe cleanup of storage resources
|
|
18
|
+
#
|
|
19
|
+
# == ⚠️ CRITICAL DATA LOSS WARNING ⚠️
|
|
20
|
+
#
|
|
21
|
+
# **DESTRUCTIVE OPERATION - PERMANENT DATA LOSS**
|
|
22
|
+
#
|
|
23
|
+
# This operation permanently and irreversibly deletes data:
|
|
24
|
+
# - **ALL DATA** in the volume is deleted forever
|
|
25
|
+
# - No recovery possible after deletion
|
|
26
|
+
# - Applications may lose critical data
|
|
27
|
+
# - Databases and persistent state are destroyed
|
|
28
|
+
# - Configuration files and user data are lost
|
|
29
|
+
# - Operation cannot be undone
|
|
30
|
+
#
|
|
31
|
+
# == Volume Dependencies
|
|
32
|
+
#
|
|
33
|
+
# Volumes may have active dependencies:
|
|
34
|
+
# - **Running Containers**: Containers currently using the volume
|
|
35
|
+
# - **Stopped Containers**: Containers that could be restarted
|
|
36
|
+
# - **Application Data**: Critical application state and databases
|
|
37
|
+
# - **User Data**: User-generated content and files
|
|
38
|
+
#
|
|
39
|
+
# == Security Considerations
|
|
40
|
+
#
|
|
41
|
+
# Volume removal has security implications:
|
|
42
|
+
# - Sensitive data is not securely wiped
|
|
43
|
+
# - Data may be recoverable from disk sectors
|
|
44
|
+
# - Shared volumes may affect multiple applications
|
|
45
|
+
# - Removal logs may reveal data existence
|
|
46
|
+
#
|
|
47
|
+
# Critical security measures:
|
|
48
|
+
# - **Backup critical data** before removal
|
|
49
|
+
# - Verify no containers depend on the volume
|
|
50
|
+
# - Consider secure data wiping for sensitive volumes
|
|
51
|
+
# - Audit volume removal operations
|
|
52
|
+
# - Monitor for unauthorized volume deletions
|
|
53
|
+
#
|
|
54
|
+
# == Force Removal Risks
|
|
55
|
+
#
|
|
56
|
+
# Force removal bypasses safety checks:
|
|
57
|
+
# - Removes volumes even if containers are using them
|
|
58
|
+
# - Can cause immediate application failures
|
|
59
|
+
# - May corrupt running applications
|
|
60
|
+
# - Data loss occurs immediately
|
|
61
|
+
#
|
|
62
|
+
# == Example Usage
|
|
63
|
+
#
|
|
64
|
+
# # Safe removal of unused volume
|
|
65
|
+
# RemoveVolume.call(
|
|
66
|
+
# server_context: context,
|
|
67
|
+
# name: "temp-data"
|
|
68
|
+
# )
|
|
69
|
+
#
|
|
70
|
+
# # Force removal of volume in use (DANGEROUS)
|
|
71
|
+
# RemoveVolume.call(
|
|
72
|
+
# server_context: context,
|
|
73
|
+
# name: "stuck-volume",
|
|
74
|
+
# force: true
|
|
75
|
+
# )
|
|
76
|
+
#
|
|
77
|
+
# @see CreateVolume
|
|
78
|
+
# @see ListVolumes
|
|
79
|
+
# @see Docker::Volume#remove
|
|
80
|
+
# @since 0.1.0
|
|
81
|
+
class RemoveVolume < RubyLLM::Tool
|
|
82
|
+
description 'Remove a Docker volume'
|
|
83
|
+
|
|
84
|
+
param :name, type: :string, desc: 'Volume name'
|
|
85
|
+
param :force, type: :boolean, desc: 'Force removal of the volume (default: false)', required: false
|
|
86
|
+
|
|
87
|
+
# Remove a Docker volume permanently from the system.
|
|
88
|
+
#
|
|
89
|
+
# This method permanently deletes the specified volume and all data
|
|
90
|
+
# contained within it. By default, it performs safety checks to prevent
|
|
91
|
+
# removal of volumes with active container dependencies.
|
|
92
|
+
#
|
|
93
|
+
# @param name [String] name of the volume to remove
|
|
94
|
+
# @param server_context [Object] RubyLLM context (unused but required)
|
|
95
|
+
# @param force [Boolean] whether to force removal despite dependencies (default: false)
|
|
96
|
+
#
|
|
97
|
+
# @return [RubyLLM::Tool::Response] removal operation results
|
|
98
|
+
#
|
|
99
|
+
# @raise [Docker::Error::NotFoundError] if volume doesn't exist
|
|
100
|
+
# @raise [StandardError] for removal failures or dependency conflicts
|
|
101
|
+
#
|
|
102
|
+
# @example Remove unused volume
|
|
103
|
+
# response = RemoveVolume.call(
|
|
104
|
+
# server_context: context,
|
|
105
|
+
# name: "old-cache-data"
|
|
106
|
+
# )
|
|
107
|
+
#
|
|
108
|
+
# @example Force remove problematic volume
|
|
109
|
+
# response = tool.execute(
|
|
110
|
+
# name: "corrupted-volume",
|
|
111
|
+
# force: true
|
|
112
|
+
# )
|
|
113
|
+
#
|
|
114
|
+
# @see Docker::Volume#remove
|
|
115
|
+
def execute(name:, force: false)
|
|
116
|
+
volume = ::Docker::Volume.get(name)
|
|
117
|
+
volume.remove(force: force)
|
|
118
|
+
|
|
119
|
+
"Volume #{name} removed successfully"
|
|
120
|
+
rescue ::Docker::Error::NotFoundError
|
|
121
|
+
"Volume #{name} not found"
|
|
122
|
+
rescue StandardError => e
|
|
123
|
+
"Error removing volume: #{e.message}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Docker
|
|
5
|
+
# RubyLLM tool for running Docker containers (create and start in one operation).
|
|
6
|
+
#
|
|
7
|
+
# This tool provides a convenient way to create and immediately start Docker
|
|
8
|
+
# containers from images. It combines the functionality of container creation
|
|
9
|
+
# and startup into a single operation, which is the most common use case for
|
|
10
|
+
# Docker containers.
|
|
11
|
+
#
|
|
12
|
+
# == Features
|
|
13
|
+
#
|
|
14
|
+
# - Create and start containers in one operation
|
|
15
|
+
# - Full support for container configuration options
|
|
16
|
+
# - Port mapping and network configuration
|
|
17
|
+
# - Volume mounting capabilities
|
|
18
|
+
# - Environment variable configuration
|
|
19
|
+
# - Custom command execution
|
|
20
|
+
# - Comprehensive error handling
|
|
21
|
+
#
|
|
22
|
+
# == Security Considerations
|
|
23
|
+
#
|
|
24
|
+
# - Containers inherit Docker daemon privileges
|
|
25
|
+
# - Port mappings expose services to host network
|
|
26
|
+
# - Volume mounts provide filesystem access
|
|
27
|
+
# - Environment variables may contain sensitive data
|
|
28
|
+
# - Custom commands can execute arbitrary code
|
|
29
|
+
#
|
|
30
|
+
# Use appropriate security measures:
|
|
31
|
+
# - Run containers with minimal required privileges
|
|
32
|
+
# - Limit port exposure to necessary services only
|
|
33
|
+
# - Use read-only volumes where possible
|
|
34
|
+
# - Avoid mounting sensitive host directories
|
|
35
|
+
# - Validate environment variables for secrets
|
|
36
|
+
#
|
|
37
|
+
# == Example Usage
|
|
38
|
+
#
|
|
39
|
+
# # Simple container run
|
|
40
|
+
# RunContainer.call(
|
|
41
|
+
# server_context: context,
|
|
42
|
+
# image: "nginx:latest",
|
|
43
|
+
# name: "web-server"
|
|
44
|
+
# )
|
|
45
|
+
#
|
|
46
|
+
# # Advanced configuration with ports and volumes
|
|
47
|
+
# RunContainer.call(
|
|
48
|
+
# server_context: context,
|
|
49
|
+
# image: "postgres:13",
|
|
50
|
+
# name: "database",
|
|
51
|
+
# env: ["POSTGRES_PASSWORD=secret"],
|
|
52
|
+
# host_config: {
|
|
53
|
+
# "PortBindings" => {"5432/tcp" => [{"HostPort" => "5432"}]},
|
|
54
|
+
# "Binds" => ["/host/data:/var/lib/postgresql/data"]
|
|
55
|
+
# }
|
|
56
|
+
# )
|
|
57
|
+
#
|
|
58
|
+
# @see CreateContainer
|
|
59
|
+
# @see StartContainer
|
|
60
|
+
# @see Docker::Container.create
|
|
61
|
+
# @since 0.1.0
|
|
62
|
+
class RunContainer < RubyLLM::Tool
|
|
63
|
+
description 'Run a Docker container (create and start)'
|
|
64
|
+
|
|
65
|
+
param :image, desc: 'Image name to use (e.g., "ubuntu:22.04")'
|
|
66
|
+
param :name, desc: 'Container name (optional)', required: false
|
|
67
|
+
param :cmd, desc: 'Command to run (optional)', required: false
|
|
68
|
+
param :env,
|
|
69
|
+
desc: 'Environment variables as comma-separated KEY=VALUE pairs ' \
|
|
70
|
+
'(optional, e.g., "VAR1=value1,VAR2=value2")',
|
|
71
|
+
required: false
|
|
72
|
+
param :exposed_ports, desc: 'Exposed ports as JSON object (optional)', required: false
|
|
73
|
+
param :host_config, desc: 'Host configuration including port bindings, volumes, etc.',
|
|
74
|
+
required: false
|
|
75
|
+
|
|
76
|
+
def execute(image:, name: nil, cmd: nil, env: nil, exposed_ports: nil, host_config: nil)
|
|
77
|
+
config = { 'Image' => image }
|
|
78
|
+
config['name'] = name if name
|
|
79
|
+
config['Cmd'] = cmd if cmd
|
|
80
|
+
|
|
81
|
+
# Parse environment variables string into array if provided
|
|
82
|
+
if env && !env.empty?
|
|
83
|
+
env_array = env.split(',').map(&:strip).select { |e| e.include?('=') }
|
|
84
|
+
config['Env'] = env_array unless env_array.empty?
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
config['ExposedPorts'] = exposed_ports if exposed_ports
|
|
88
|
+
config['HostConfig'] = host_config if host_config
|
|
89
|
+
|
|
90
|
+
container = ::Docker::Container.create(config)
|
|
91
|
+
container.start
|
|
92
|
+
container_name = container.info['Names']&.first&.delete_prefix('/')
|
|
93
|
+
|
|
94
|
+
"Container started successfully. ID: #{container.id}, Name: #{container_name}"
|
|
95
|
+
rescue ::Docker::Error::NotFoundError
|
|
96
|
+
"Image #{image} not found"
|
|
97
|
+
rescue ::Docker::Error::ConflictError
|
|
98
|
+
"Container with name #{name} already exists"
|
|
99
|
+
rescue StandardError => e
|
|
100
|
+
"Error running container: #{e.message}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Docker
|
|
5
|
+
# RubyLLM tool for starting existing Docker containers.
|
|
6
|
+
#
|
|
7
|
+
# This tool provides the ability to start Docker containers that have been
|
|
8
|
+
# created but are currently stopped. It's the counterpart to StopContainer
|
|
9
|
+
# and is commonly used after CreateContainer or when restarting stopped
|
|
10
|
+
# containers.
|
|
11
|
+
#
|
|
12
|
+
# == Features
|
|
13
|
+
#
|
|
14
|
+
# - Start stopped containers by ID or name
|
|
15
|
+
# - Simple and reliable container lifecycle management
|
|
16
|
+
# - Comprehensive error handling
|
|
17
|
+
# - Works with containers in any stopped state
|
|
18
|
+
#
|
|
19
|
+
# == Security Considerations
|
|
20
|
+
#
|
|
21
|
+
# Starting containers can have security implications:
|
|
22
|
+
# - Containers resume with their original configuration
|
|
23
|
+
# - Services become accessible on mapped ports
|
|
24
|
+
# - Processes resume execution with previous privileges
|
|
25
|
+
# - Network connections are re-established
|
|
26
|
+
#
|
|
27
|
+
# Ensure containers are properly configured before starting:
|
|
28
|
+
# - Review port mappings and network exposure
|
|
29
|
+
# - Verify volume mounts and file permissions
|
|
30
|
+
# - Check environment variables for sensitive data
|
|
31
|
+
# - Validate container image integrity
|
|
32
|
+
#
|
|
33
|
+
# == Example Usage
|
|
34
|
+
#
|
|
35
|
+
# # Start container by name
|
|
36
|
+
# StartContainer.call(
|
|
37
|
+
# server_context: context,
|
|
38
|
+
# id: "web-server"
|
|
39
|
+
# )
|
|
40
|
+
#
|
|
41
|
+
# # Start container by ID
|
|
42
|
+
# StartContainer.call(
|
|
43
|
+
# server_context: context,
|
|
44
|
+
# id: "a1b2c3d4e5f6"
|
|
45
|
+
# )
|
|
46
|
+
#
|
|
47
|
+
# @see CreateContainer
|
|
48
|
+
# @see StopContainer
|
|
49
|
+
# @see RunContainer
|
|
50
|
+
# @see Docker::Container#start
|
|
51
|
+
# @since 0.1.0
|
|
52
|
+
class StartContainer < RubyLLM::Tool
|
|
53
|
+
description 'Start a Docker container'
|
|
54
|
+
|
|
55
|
+
param :id, desc: 'Container ID or name'
|
|
56
|
+
|
|
57
|
+
# Start an existing Docker container.
|
|
58
|
+
#
|
|
59
|
+
# This method starts a container that is currently in a stopped state.
|
|
60
|
+
# The container must already exist and be in a startable state. If the
|
|
61
|
+
# container is already running, Docker will typically ignore the start
|
|
62
|
+
# command without error.
|
|
63
|
+
#
|
|
64
|
+
# @param id [String] container ID (full or short) or container name
|
|
65
|
+
# @param server_context [Object] RubyLLM context (unused but required)
|
|
66
|
+
#
|
|
67
|
+
# @return [RubyLLM::Tool::Response] start operation results
|
|
68
|
+
#
|
|
69
|
+
# @raise [Docker::Error::NotFoundError] if container doesn't exist
|
|
70
|
+
# @raise [StandardError] for other start failures
|
|
71
|
+
#
|
|
72
|
+
# @example Start by container name
|
|
73
|
+
# response = StartContainer.call(
|
|
74
|
+
# server_context: context,
|
|
75
|
+
# id: "my-app-container"
|
|
76
|
+
# )
|
|
77
|
+
#
|
|
78
|
+
# @example Start by container ID
|
|
79
|
+
# response = StartContainer.call(
|
|
80
|
+
# server_context: context,
|
|
81
|
+
# id: "abc123def456"
|
|
82
|
+
# )
|
|
83
|
+
#
|
|
84
|
+
# @see Docker::Container#start
|
|
85
|
+
def execute(id:)
|
|
86
|
+
container = ::Docker::Container.get(id)
|
|
87
|
+
container.start
|
|
88
|
+
|
|
89
|
+
"Container #{id} started successfully"
|
|
90
|
+
rescue ::Docker::Error::NotFoundError
|
|
91
|
+
"Container #{id} not found"
|
|
92
|
+
rescue StandardError => e
|
|
93
|
+
"Error starting container: #{e.message}"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyLLM
|
|
4
|
+
module Docker
|
|
5
|
+
# RubyLLM tool for stopping running Docker containers.
|
|
6
|
+
#
|
|
7
|
+
# This tool provides the ability to gracefully stop running Docker containers
|
|
8
|
+
# with configurable timeout handling. It sends a SIGTERM signal to the main
|
|
9
|
+
# process and waits for the specified timeout before forcibly killing the
|
|
10
|
+
# container with SIGKILL.
|
|
11
|
+
#
|
|
12
|
+
# == Features
|
|
13
|
+
#
|
|
14
|
+
# - Graceful container shutdown with SIGTERM
|
|
15
|
+
# - Configurable timeout before force kill
|
|
16
|
+
# - Works with containers by ID or name
|
|
17
|
+
# - Comprehensive error handling
|
|
18
|
+
# - Safe for already stopped containers
|
|
19
|
+
#
|
|
20
|
+
# == Shutdown Process
|
|
21
|
+
#
|
|
22
|
+
# 1. Send SIGTERM to container's main process
|
|
23
|
+
# 2. Wait for graceful shutdown up to timeout
|
|
24
|
+
# 3. Send SIGKILL if container hasn't stopped
|
|
25
|
+
# 4. Return success when container is stopped
|
|
26
|
+
#
|
|
27
|
+
# == Security Considerations
|
|
28
|
+
#
|
|
29
|
+
# Stopping containers affects service availability:
|
|
30
|
+
# - Services become unavailable immediately
|
|
31
|
+
# - Network connections are terminated
|
|
32
|
+
# - Data may be lost if not properly persisted
|
|
33
|
+
# - Dependent services may be affected
|
|
34
|
+
#
|
|
35
|
+
# Best practices:
|
|
36
|
+
# - Ensure data persistence before stopping
|
|
37
|
+
# - Consider impact on dependent services
|
|
38
|
+
# - Use appropriate timeout for graceful shutdown
|
|
39
|
+
# - Monitor application logs during shutdown
|
|
40
|
+
#
|
|
41
|
+
# == Example Usage
|
|
42
|
+
#
|
|
43
|
+
# # Stop with default timeout (10 seconds)
|
|
44
|
+
# StopContainer.call(
|
|
45
|
+
# server_context: context,
|
|
46
|
+
# id: "web-server"
|
|
47
|
+
# )
|
|
48
|
+
#
|
|
49
|
+
# # Stop with custom timeout
|
|
50
|
+
# StopContainer.call(
|
|
51
|
+
# server_context: context,
|
|
52
|
+
# id: "database",
|
|
53
|
+
# timeout: 30
|
|
54
|
+
# )
|
|
55
|
+
#
|
|
56
|
+
# @see StartContainer
|
|
57
|
+
# @see RemoveContainer
|
|
58
|
+
# @see Docker::Container#stop
|
|
59
|
+
# @since 0.1.0
|
|
60
|
+
class StopContainer < RubyLLM::Tool
|
|
61
|
+
description 'Stop a Docker container'
|
|
62
|
+
|
|
63
|
+
param :id, desc: 'Container ID or name'
|
|
64
|
+
param :timeout, type: :integer, desc: 'Seconds to wait before killing the container (default: 10)',
|
|
65
|
+
required: false
|
|
66
|
+
|
|
67
|
+
# Stop a running Docker container gracefully.
|
|
68
|
+
#
|
|
69
|
+
# This method stops a container by sending SIGTERM to the main process
|
|
70
|
+
# and waiting for the specified timeout before sending SIGKILL. The
|
|
71
|
+
# operation is idempotent - stopping an already stopped container
|
|
72
|
+
# typically succeeds without error.
|
|
73
|
+
#
|
|
74
|
+
# @param id [String] container ID (full or short) or container name
|
|
75
|
+
# @param server_context [Object] RubyLLM context (unused but required)
|
|
76
|
+
# @param timeout [Integer] seconds to wait before force killing (default: 10)
|
|
77
|
+
#
|
|
78
|
+
# @return [RubyLLM::Tool::Response] stop operation results
|
|
79
|
+
#
|
|
80
|
+
# @raise [Docker::Error::NotFoundError] if container doesn't exist
|
|
81
|
+
# @raise [StandardError] for other stop failures
|
|
82
|
+
#
|
|
83
|
+
# @example Stop with default timeout
|
|
84
|
+
# response = StopContainer.call(
|
|
85
|
+
# server_context: context,
|
|
86
|
+
# id: "nginx-server"
|
|
87
|
+
# )
|
|
88
|
+
#
|
|
89
|
+
# @example Stop database with longer timeout
|
|
90
|
+
# response = StopContainer.call(
|
|
91
|
+
# server_context: context,
|
|
92
|
+
# id: "postgres-db",
|
|
93
|
+
# timeout: 60 # Allow more time for DB shutdown
|
|
94
|
+
# )
|
|
95
|
+
#
|
|
96
|
+
# @see Docker::Container#stop
|
|
97
|
+
def execute(id:, timeout: 10)
|
|
98
|
+
container = ::Docker::Container.get(id)
|
|
99
|
+
container.stop('timeout' => timeout)
|
|
100
|
+
|
|
101
|
+
"Container #{id} stopped successfully"
|
|
102
|
+
rescue ::Docker::Error::NotFoundError
|
|
103
|
+
"Container #{id} not found"
|
|
104
|
+
rescue StandardError => e
|
|
105
|
+
"Error stopping container: #{e.message}"
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
end
|