ruby_llm-docker 0.0.1 → 0.3.0

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.
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Docker
5
+ # MCP tool for pushing Docker images to registries.
6
+ #
7
+ # This tool provides the ability to upload Docker images to Docker
8
+ # registries such as Docker Hub, private registries, or cloud-based
9
+ # container registries. It supports various push configurations and
10
+ # authentication scenarios.
11
+ #
12
+ # == Features
13
+ #
14
+ # - Push images to any Docker registry
15
+ # - Support for tagged and untagged pushes
16
+ # - Registry authentication integration
17
+ # - Comprehensive error handling and validation
18
+ # - Multi-registry support
19
+ # - Progress tracking and status reporting
20
+ # - Registry namespace validation
21
+ #
22
+ # == Security Considerations
23
+ #
24
+ # Pushing images involves significant security risks:
25
+ # - **Credential Exposure**: Registry credentials may be exposed
26
+ # - **Image Integrity**: Pushed images become publicly accessible
27
+ # - **Supply Chain Risk**: Malicious images can be distributed
28
+ # - **Registry Security**: Vulnerable registries can be compromised
29
+ # - **Network Exposure**: Push operations traverse networks
30
+ # - **Access Control**: Improper permissions can lead to unauthorized access
31
+ #
32
+ # **Security Recommendations**:
33
+ # - Use secure registry authentication
34
+ # - Scan images for vulnerabilities before pushing
35
+ # - Implement image signing and verification
36
+ # - Use private registries for sensitive images
37
+ # - Monitor registry access and usage
38
+ # - Implement proper RBAC for registry operations
39
+ # - Validate image content before distribution
40
+ #
41
+ # == Parameters
42
+ #
43
+ # - **name**: Image name or ID to push (required)
44
+ # - **tag**: Tag to push (optional, pushes all tags if not specified)
45
+ # - **repo_tag**: Full repo:tag to push (optional, e.g., "registry/repo:tag")
46
+ #
47
+ # == Example Usage
48
+ #
49
+ # # Push to Docker Hub
50
+ # response = PushImage.call(
51
+ # server_context: context,
52
+ # name: "username/myapp",
53
+ # tag: "v1.0.0"
54
+ # )
55
+ #
56
+ # # Push to private registry
57
+ # response = PushImage.call(
58
+ # server_context: context,
59
+ # name: "myapp",
60
+ # repo_tag: "registry.company.com/team/myapp:latest"
61
+ # )
62
+ #
63
+ # # Push all tags
64
+ # response = PushImage.call(
65
+ # server_context: context,
66
+ # name: "username/myapp"
67
+ # )
68
+ #
69
+ # @see Docker CLI push command
70
+ # @since 0.1.0
71
+ PUSH_IMAGE_DEFINITION = ToolForge.define(:push_image) do
72
+ description 'Push a Docker image'
73
+
74
+ param :name,
75
+ type: :string,
76
+ description: 'Image name or ID to push'
77
+
78
+ param :tag,
79
+ type: :string,
80
+ description: 'Tag to push (optional, pushes all tags if not specified)',
81
+ required: false
82
+
83
+ param :repo_tag,
84
+ type: :string,
85
+ description: 'Full repo:tag to push (e.g., "registry/repo:tag") (optional)',
86
+ required: false
87
+
88
+ execute do |name:, tag: nil, repo_tag: nil|
89
+ # Construct the full image identifier
90
+ image_identifier = tag ? "#{name}:#{tag}" : name
91
+
92
+ # Validate that the image name includes a registry/username
93
+ unless name.include?('/') || repo_tag&.include?('/')
94
+ next 'Error: Image name must include registry/username ' \
95
+ "(e.g., 'username/#{name}'). Local images cannot be " \
96
+ 'pushed without a registry prefix.'
97
+ end
98
+
99
+ # Verify the image exists
100
+ begin
101
+ ::Docker::Image.get(image_identifier)
102
+ rescue ::Docker::Error::NotFoundError
103
+ next "Image #{image_identifier} not found"
104
+ end
105
+
106
+ # Use the Docker CLI to push the image
107
+ push_target = repo_tag || image_identifier
108
+ _, stderr, status = Open3.capture3('docker', 'push', push_target)
109
+
110
+ if status.success?
111
+ "Image #{push_target} pushed successfully"
112
+ else
113
+ error_msg = stderr.strip
114
+ error_msg = 'Failed to push image' if error_msg.empty?
115
+ "Error pushing image: #{error_msg}"
116
+ end
117
+ rescue StandardError => e
118
+ "Error pushing image: #{e.message}"
119
+ end
120
+ end
121
+
122
+ PushImage = PUSH_IMAGE_DEFINITION.to_ruby_llm_tool
123
+ end
124
+ end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Docker
5
+ # MCP tool for recreating Docker containers.
6
+ #
7
+ # This tool provides a complete container recreation process that stops
8
+ # the existing container, removes it, and creates a new container with
9
+ # the same configuration. This is useful for applying image updates,
10
+ # clearing container state, or resolving container corruption issues.
11
+ #
12
+ # == Features
13
+ #
14
+ # - Complete container recreation with preserved configuration
15
+ # - Automatic stop, remove, and recreate sequence
16
+ # - Preserves original container configuration and settings
17
+ # - Configurable stop timeout for graceful shutdown
18
+ # - Handles both running and stopped containers
19
+ # - Maintains container networking and volume configurations
20
+ #
21
+ # == Security Considerations
22
+ #
23
+ # Container recreation involves several security considerations:
24
+ # - **Service Downtime**: Temporary service interruption during recreation
25
+ # - **Data Loss**: Container file system changes are lost (volumes preserved)
26
+ # - **Resource Allocation**: New container may have different resource usage
27
+ # - **Network Reconfiguration**: IP addresses may change
28
+ # - **State Reset**: Application state within container is lost
29
+ #
30
+ # Plan recreations carefully and coordinate with dependent services.
31
+ #
32
+ # == Parameters
33
+ #
34
+ # - **id**: Container ID or name to recreate (required)
35
+ # - **timeout**: Seconds to wait before killing container when stopping (optional, default: 10)
36
+ #
37
+ # == Process Flow
38
+ #
39
+ # 1. Inspect existing container to capture configuration
40
+ # 2. Stop the running container (if running)
41
+ # 3. Remove the stopped container
42
+ # 4. Create new container with captured configuration
43
+ # 5. Return new container information
44
+ #
45
+ # == Example Usage
46
+ #
47
+ # # Recreate with default timeout
48
+ # response = RecreateContainer.call(
49
+ # server_context: context,
50
+ # id: "web-server"
51
+ # )
52
+ #
53
+ # # Recreate with extended timeout
54
+ # response = RecreateContainer.call(
55
+ # server_context: context,
56
+ # id: "database",
57
+ # timeout: 30
58
+ # )
59
+ #
60
+ # @see ::Docker::Container#stop
61
+ # @see ::Docker::Container#remove
62
+ # @see ::Docker::Container.create
63
+ # @since 0.1.0
64
+ RECREATE_CONTAINER_DEFINITION = ToolForge.define(:recreate_container) do
65
+ description 'Recreate a Docker container (stops, removes, and recreates with same configuration)'
66
+
67
+ param :id,
68
+ type: :string,
69
+ description: 'Container ID or name to recreate'
70
+
71
+ param :timeout,
72
+ type: :integer,
73
+ description: 'Seconds to wait before killing the container when stopping (default: 10)',
74
+ required: false,
75
+ default: 10
76
+
77
+ execute do |id:, timeout: 10|
78
+ # Get the existing container
79
+ old_container = ::Docker::Container.get(id)
80
+ config = old_container.json
81
+
82
+ # Extract configuration we need to preserve
83
+ image = config['Config']['Image']
84
+ name = config['Name']&.delete_prefix('/')
85
+ cmd = config['Config']['Cmd']
86
+ env = config['Config']['Env']
87
+ exposed_ports = config['Config']['ExposedPorts']
88
+ host_config = config['HostConfig']
89
+
90
+ # Stop and remove the old container
91
+ old_container.stop('timeout' => timeout) if config['State']['Running']
92
+ old_container.delete
93
+
94
+ # Create new container with same config
95
+ new_config = {
96
+ 'Image' => image,
97
+ 'Cmd' => cmd,
98
+ 'Env' => env,
99
+ 'ExposedPorts' => exposed_ports,
100
+ 'HostConfig' => host_config
101
+ }
102
+ new_config['name'] = name if name
103
+
104
+ new_container = ::Docker::Container.create(new_config)
105
+
106
+ # Start if the old one was running
107
+ new_container.start if config['State']['Running']
108
+
109
+ "Container #{id} recreated successfully. New ID: #{new_container.id}"
110
+ rescue ::Docker::Error::NotFoundError
111
+ "Container #{id} not found"
112
+ rescue StandardError => e
113
+ "Error recreating container: #{e.message}"
114
+ end
115
+ end
116
+
117
+ RecreateContainer = RECREATE_CONTAINER_DEFINITION.to_ruby_llm_tool
118
+ end
119
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Docker
5
+ # MCP tool for removing Docker containers.
6
+ #
7
+ # This tool permanently removes a Docker container from the system,
8
+ # including its file system, configuration, and metadata. This is a
9
+ # destructive operation that cannot be undone. The container must
10
+ # be stopped before removal unless force is specified.
11
+ #
12
+ # == Features
13
+ #
14
+ # - Permanent container removal from system
15
+ # - Supports forced removal of running containers
16
+ # - Optional removal of associated volumes
17
+ # - Handles container identification by ID or name
18
+ # - Provides comprehensive error handling
19
+ # - Frees all associated system resources
20
+ #
21
+ # == Security Considerations
22
+ #
23
+ # Container removal is a destructive operation with implications:
24
+ # - **Data Loss**: Permanently destroys container file system
25
+ # - **Configuration Loss**: Removes container settings and metadata
26
+ # - **Service Disruption**: Eliminates containerized services
27
+ # - **Resource Recovery**: Frees storage, memory, and system resources
28
+ # - **Audit Trail**: May remove forensic evidence if needed
29
+ #
30
+ # Implement proper backup and approval workflows for production systems.
31
+ #
32
+ # == Parameters
33
+ #
34
+ # - **id**: Container ID or name (required)
35
+ # - Accepts full container IDs
36
+ # - Accepts short container IDs (first 12+ characters)
37
+ # - Accepts custom container names
38
+ # - **force**: Force removal of running container (optional, default: false)
39
+ # - **volumes**: Remove associated volumes (optional, default: false)
40
+ #
41
+ # == Example Usage
42
+ #
43
+ # # Remove stopped container
44
+ # response = RemoveContainer.call(
45
+ # server_context: context,
46
+ # id: "old-web-server"
47
+ # )
48
+ #
49
+ # # Force remove running container with volumes
50
+ # response = RemoveContainer.call(
51
+ # server_context: context,
52
+ # id: "problematic-container",
53
+ # force: true,
54
+ # volumes: true
55
+ # )
56
+ #
57
+ # @see ::Docker::Container#remove
58
+ # @since 0.1.0
59
+ REMOVE_CONTAINER_DEFINITION = ToolForge.define(:remove_container) do
60
+ description 'Remove a Docker container'
61
+
62
+ param :id,
63
+ type: :string,
64
+ description: 'Container ID or name'
65
+
66
+ param :force,
67
+ type: :boolean,
68
+ description: 'Force removal of running container (default: false)',
69
+ required: false,
70
+ default: false
71
+
72
+ param :volumes,
73
+ type: :boolean,
74
+ description: 'Remove associated volumes (default: false)',
75
+ required: false,
76
+ default: false
77
+
78
+ execute do |id:, force: false, volumes: false|
79
+ container = ::Docker::Container.get(id)
80
+ container.delete(force: force, v: volumes)
81
+
82
+ "Container #{id} removed successfully"
83
+ rescue ::Docker::Error::NotFoundError
84
+ "Container #{id} not found"
85
+ rescue StandardError => e
86
+ "Error removing container: #{e.message}"
87
+ end
88
+ end
89
+
90
+ RemoveContainer = REMOVE_CONTAINER_DEFINITION.to_ruby_llm_tool
91
+ end
92
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Docker
5
+ # MCP tool for removing Docker images.
6
+ #
7
+ # This tool provides the ability to delete Docker images from the
8
+ # local Docker daemon. It supports various removal options including
9
+ # forced removal and parent image cleanup management.
10
+ #
11
+ # == Features
12
+ #
13
+ # - Remove images by ID, name, or tag
14
+ # - Force removal of images in use
15
+ # - Control untagged parent image cleanup
16
+ # - Comprehensive error handling
17
+ # - Validation of image existence
18
+ # - Safe removal with dependency checking
19
+ #
20
+ # == Security Considerations
21
+ #
22
+ # Image removal involves important considerations:
23
+ # - **Data Loss**: Removed images cannot be recovered locally
24
+ # - **Service Disruption**: Removing images used by running containers
25
+ # - **Storage Cleanup**: Improper cleanup can leave orphaned layers
26
+ # - **Registry Impact**: Local removal doesn't affect registry copies
27
+ # - **Dependency Conflicts**: Force removal can break container dependencies
28
+ #
29
+ # **Security Recommendations**:
30
+ # - Verify image is not in use before removal
31
+ # - Use force option only when necessary
32
+ # - Consider impact on running containers
33
+ # - Backup important images before removal
34
+ # - Monitor disk space after removal operations
35
+ # - Implement image lifecycle policies
36
+ #
37
+ # == Parameters
38
+ #
39
+ # - **id**: Image ID, name, or name:tag (required)
40
+ # - **force**: Force removal of the image (optional, default: false)
41
+ # - **noprune**: Do not delete untagged parents (optional, default: false)
42
+ #
43
+ # == Example Usage
44
+ #
45
+ # # Remove specific image
46
+ # response = RemoveImage.call(
47
+ # server_context: context,
48
+ # id: "myapp:old-version"
49
+ # )
50
+ #
51
+ # # Force remove image in use
52
+ # response = RemoveImage.call(
53
+ # server_context: context,
54
+ # id: "abc123def456",
55
+ # force: true
56
+ # )
57
+ #
58
+ # # Remove without cleaning parent images
59
+ # response = RemoveImage.call(
60
+ # server_context: context,
61
+ # id: "test-image:latest",
62
+ # noprune: true
63
+ # )
64
+ #
65
+ # @see ::Docker::Image#remove
66
+ # @since 0.1.0
67
+ REMOVE_IMAGE_DEFINITION = ToolForge.define(:remove_image) do
68
+ description 'Remove a Docker image'
69
+
70
+ param :id,
71
+ type: :string,
72
+ description: 'Image ID, name, or name:tag'
73
+
74
+ param :force,
75
+ type: :boolean,
76
+ description: 'Force removal of the image (default: false)',
77
+ required: false,
78
+ default: false
79
+
80
+ param :noprune,
81
+ type: :boolean,
82
+ description: 'Do not delete untagged parents (default: false)',
83
+ required: false,
84
+ default: false
85
+
86
+ execute do |id:, force: false, noprune: false|
87
+ image = ::Docker::Image.get(id)
88
+ image.remove(force: force, noprune: noprune)
89
+
90
+ "Image #{id} removed successfully"
91
+ rescue ::Docker::Error::NotFoundError
92
+ "Image #{id} not found"
93
+ rescue StandardError => e
94
+ "Error removing image: #{e.message}"
95
+ end
96
+ end
97
+
98
+ RemoveImage = REMOVE_IMAGE_DEFINITION.to_ruby_llm_tool
99
+ end
100
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Docker
5
+ # MCP tool for removing Docker networks.
6
+ #
7
+ # This tool provides the ability to delete Docker networks when they
8
+ # are no longer needed. Network removal helps maintain clean network
9
+ # configurations and prevents resource leaks.
10
+ #
11
+ # == Features
12
+ #
13
+ # - Remove networks by ID or name
14
+ # - Validation of network existence
15
+ # - Comprehensive error handling
16
+ # - Prevention of removing networks in use
17
+ # - Safe cleanup of network resources
18
+ # - Network dependency checking
19
+ #
20
+ # == Security Considerations
21
+ #
22
+ # Network removal involves important considerations:
23
+ # - **Service Disruption**: Removing active networks disconnects containers
24
+ # - **Data Isolation**: Network removal can affect container communication
25
+ # - **Resource Cleanup**: Improper removal can leave network artifacts
26
+ # - **Container Dependencies**: Containers may fail without expected networks
27
+ # - **Network Policies**: Removal affects security and access policies
28
+ #
29
+ # **Security Recommendations**:
30
+ # - Verify no containers are connected before removal
31
+ # - Check for dependent services and applications
32
+ # - Document network removal in change logs
33
+ # - Implement network lifecycle management
34
+ # - Monitor for orphaned network resources
35
+ # - Use network removal as part of cleanup procedures
36
+ #
37
+ # == Parameters
38
+ #
39
+ # - **id**: Network ID or name (required)
40
+ #
41
+ # == Example Usage
42
+ #
43
+ # # Remove network by name
44
+ # response = RemoveNetwork.call(
45
+ # server_context: context,
46
+ # id: "app-network"
47
+ # )
48
+ #
49
+ # # Remove network by ID
50
+ # response = RemoveNetwork.call(
51
+ # server_context: context,
52
+ # id: "abc123def456"
53
+ # )
54
+ #
55
+ # # Clean up test networks
56
+ # response = RemoveNetwork.call(
57
+ # server_context: context,
58
+ # id: "test-isolated-network"
59
+ # )
60
+ #
61
+ # @see ::Docker::Network#delete
62
+ # @since 0.1.0
63
+ REMOVE_NETWORK_DEFINITION = ToolForge.define(:remove_network) do
64
+ description 'Remove a Docker network'
65
+
66
+ param :id,
67
+ type: :string,
68
+ description: 'Network ID or name'
69
+
70
+ execute do |id:|
71
+ network = ::Docker::Network.get(id)
72
+ network.delete
73
+
74
+ "Network #{id} removed successfully"
75
+ rescue ::Docker::Error::NotFoundError
76
+ "Network #{id} not found"
77
+ rescue StandardError => e
78
+ "Error removing network: #{e.message}"
79
+ end
80
+ end
81
+
82
+ RemoveNetwork = REMOVE_NETWORK_DEFINITION.to_ruby_llm_tool
83
+ end
84
+ end
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyLLM
4
+ module Docker
5
+ # MCP tool for removing Docker volumes.
6
+ #
7
+ # This tool provides the ability to delete Docker volumes when they
8
+ # are no longer needed. Volume removal is critical for preventing
9
+ # storage leaks and maintaining clean Docker environments.
10
+ #
11
+ # == Features
12
+ #
13
+ # - Remove volumes by name
14
+ # - Force removal of volumes in use
15
+ # - Validation of volume existence
16
+ # - Comprehensive error handling
17
+ # - Safe volume cleanup procedures
18
+ # - Prevention of accidental data loss
19
+ #
20
+ # == Security Considerations
21
+ #
22
+ # Volume removal involves critical data considerations:
23
+ # - **Data Loss**: Removed volumes and their data are permanently deleted
24
+ # - **Service Disruption**: Removing volumes can break running containers
25
+ # - **Data Recovery**: Volume data cannot be recovered after removal
26
+ # - **Container Dependencies**: Applications may fail without expected volumes
27
+ # - **Storage Cleanup**: Improper removal can leave orphaned data
28
+ # - **Backup Requirements**: Critical data should be backed up before removal
29
+ #
30
+ # **Security Recommendations**:
31
+ # - Always backup critical data before volume removal
32
+ # - Verify no containers are using the volume
33
+ # - Use force option only when absolutely necessary
34
+ # - Document volume removal in change management
35
+ # - Implement volume lifecycle and retention policies
36
+ # - Monitor storage usage after volume removal
37
+ # - Consider data migration instead of removal
38
+ #
39
+ # == Parameters
40
+ #
41
+ # - **name**: Volume name (required)
42
+ # - **force**: Force removal of the volume (optional, default: false)
43
+ #
44
+ # == Example Usage
45
+ #
46
+ # # Remove unused volume
47
+ # response = RemoveVolume.call(
48
+ # server_context: context,
49
+ # name: "old-app-data"
50
+ # )
51
+ #
52
+ # # Force remove volume in use
53
+ # response = RemoveVolume.call(
54
+ # server_context: context,
55
+ # name: "stuck-volume",
56
+ # force: true
57
+ # )
58
+ #
59
+ # # Clean up test volumes
60
+ # response = RemoveVolume.call(
61
+ # server_context: context,
62
+ # name: "test-data-volume"
63
+ # )
64
+ #
65
+ # @see ::Docker::Volume#remove
66
+ # @since 0.1.0
67
+ REMOVE_VOLUME_DEFINITION = ToolForge.define(:remove_volume) do
68
+ description 'Remove a Docker volume'
69
+
70
+ param :name,
71
+ type: :string,
72
+ description: 'Volume name'
73
+
74
+ param :force,
75
+ type: :boolean,
76
+ description: 'Force removal of the volume (default: false)',
77
+ required: false,
78
+ default: false
79
+
80
+ execute do |name:, force: false|
81
+ volume = ::Docker::Volume.get(name)
82
+ volume.remove(force: force)
83
+
84
+ "Volume #{name} removed successfully"
85
+ rescue ::Docker::Error::NotFoundError
86
+ "Volume #{name} not found"
87
+ rescue StandardError => e
88
+ "Error removing volume: #{e.message}"
89
+ end
90
+ end
91
+
92
+ RemoveVolume = REMOVE_VOLUME_DEFINITION.to_ruby_llm_tool
93
+ end
94
+ end