Enhance Config and Manager for Container Path Management

- Added ContainerWorkDir and ContainerIPCSocket fields to the Config struct for better container path configuration.
- Updated DefaultConfig to initialize new fields with default values.
- Modified the Manager to apply defaults for container paths and utilize them in container creation and execution methods, improving flexibility and reliability in container management.
This commit is contained in:
Max 2026-01-29 19:53:30 +08:00
parent 1ece4b0f48
commit 0394727f29
2 changed files with 59 additions and 14 deletions

View file

@ -16,6 +16,10 @@ type Config struct {
IdleTimeout time.Duration `json:"idle_timeout,omitempty"` // Idle timeout before stopping container IdleTimeout time.Duration `json:"idle_timeout,omitempty"` // Idle timeout before stopping container
MaxMemory string `json:"max_memory,omitempty"` // Memory limit, e.g., "2g" MaxMemory string `json:"max_memory,omitempty"` // Memory limit, e.g., "2g"
MaxCPU float64 `json:"max_cpu,omitempty"` // CPU limit, e.g., 1.0 MaxCPU float64 `json:"max_cpu,omitempty"` // CPU limit, e.g., 1.0
// Container internal paths
ContainerWorkDir string `json:"container_workdir,omitempty"` // Container working directory, default: /workspace
ContainerIPCSocket string `json:"container_ipc_socket,omitempty"` // Container IPC socket path, default: /tmp/yao.sock
} }
// DefaultConfig returns a Config with default values // DefaultConfig returns a Config with default values
@ -26,6 +30,8 @@ func DefaultConfig() *Config {
IdleTimeout: 30 * time.Minute, IdleTimeout: 30 * time.Minute,
MaxMemory: "2g", MaxMemory: "2g",
MaxCPU: 1.0, MaxCPU: 1.0,
ContainerWorkDir: "/workspace",
ContainerIPCSocket: "/tmp/yao.sock",
} }
} }
@ -91,4 +97,17 @@ func (c *Config) Init(dataRoot string) {
} }
// Invalid env value: keep existing/default value // Invalid env value: keep existing/default value
} }
// Container internal paths
if env := os.Getenv("YAO_SANDBOX_CONTAINER_WORKDIR"); env != "" {
c.ContainerWorkDir = env
} else if c.ContainerWorkDir == "" {
c.ContainerWorkDir = "/workspace"
}
if env := os.Getenv("YAO_SANDBOX_CONTAINER_IPC"); env != "" {
c.ContainerIPCSocket = env
} else if c.ContainerIPCSocket == "" {
c.ContainerIPCSocket = "/tmp/yao.sock"
}
} }

View file

@ -48,6 +48,14 @@ func NewManager(config *Config) (*Manager, error) {
config = DefaultConfig() config = DefaultConfig()
} }
// Apply defaults for missing container paths
if config.ContainerWorkDir == "" {
config.ContainerWorkDir = "/workspace"
}
if config.ContainerIPCSocket == "" {
config.ContainerIPCSocket = "/tmp/yao.sock"
}
// Initialize Docker client // Initialize Docker client
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
if err != nil { if err != nil {
@ -153,18 +161,23 @@ func (m *Manager) createContainer(ctx context.Context, userID, chatID string) (*
containerConfig := &container.Config{ containerConfig := &container.Config{
Image: m.config.Image, Image: m.config.Image,
Cmd: []string{"sleep", "infinity"}, Cmd: []string{"sleep", "infinity"},
WorkingDir: "/workspace", WorkingDir: m.config.ContainerWorkDir,
Env: []string{ Env: []string{
"YAO_IPC_SOCKET=/tmp/yao.sock", "YAO_IPC_SOCKET=" + m.config.ContainerIPCSocket,
}, },
} }
// Host configuration // Host configuration - only mount IPC socket if it exists
binds := []string{
workspaceHost + ":" + m.config.ContainerWorkDir,
}
// Only mount IPC socket if the file exists (it's created by IPC manager)
if _, err := os.Stat(ipcSocketHost); err == nil {
binds = append(binds, ipcSocketHost+":"+m.config.ContainerIPCSocket)
}
hostConfig := &container.HostConfig{ hostConfig := &container.HostConfig{
Binds: []string{ Binds: binds,
workspaceHost + ":/workspace",
ipcSocketHost + ":/tmp/yao.sock",
},
Resources: container.Resources{ Resources: container.Resources{
Memory: parseMemory(m.config.MaxMemory), Memory: parseMemory(m.config.MaxMemory),
NanoCPUs: int64(m.config.MaxCPU * 1e9), NanoCPUs: int64(m.config.MaxCPU * 1e9),
@ -342,7 +355,7 @@ func (m *Manager) Exec(ctx context.Context, name string, cmd []string, opts *Exe
// Default options // Default options
if opts.WorkDir == "" { if opts.WorkDir == "" {
opts.WorkDir = "/workspace" opts.WorkDir = m.config.ContainerWorkDir
} }
// Create exec instance // Create exec instance
@ -544,9 +557,22 @@ func (m *Manager) WriteFile(ctx context.Context, name, path string, content []by
// Ensure parent directory exists // Ensure parent directory exists
dir := filepath.Dir(path) dir := filepath.Dir(path)
if dir != "/" && dir != "." { if dir != "/" && dir != "." {
if _, err := m.Exec(ctx, name, []string{"mkdir", "-p", dir}, nil); err != nil { result, err := m.Exec(ctx, name, []string{"mkdir", "-p", dir}, nil)
if err != nil {
return fmt.Errorf("failed to create parent directory: %w", err) return fmt.Errorf("failed to create parent directory: %w", err)
} }
if result.ExitCode != 0 {
return fmt.Errorf("mkdir failed with exit code %d: %s", result.ExitCode, result.Stdout)
}
// Verify directory was created
verifyResult, err := m.Exec(ctx, name, []string{"test", "-d", dir}, nil)
if err != nil {
return fmt.Errorf("failed to verify directory: %w", err)
}
if verifyResult.ExitCode != 0 {
return fmt.Errorf("directory %s was not created", dir)
}
} }
// Create a tar archive with the file // Create a tar archive with the file