Skip to content

Commit 236d2c3

Browse files
julio4claude[bot]
andauthored
feat: host_path support in recipes (#401)
YAML recipes currently support named Docker volumes and session-local bind mounts, but not arbitrary host path bind mounts. This is needed for services that require access to host resources. Concrete use case: log collections with docker socket, hot binary reload - Add host_path field to volume config, enabling direct host-to-container bind mounts (e.g. /var/run/docker.sock) - Existing volume types (name/is_local) are unchanged --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
1 parent 4b5772b commit 236d2c3

4 files changed

Lines changed: 50 additions & 11 deletions

File tree

playground/local_runner.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -684,6 +684,11 @@ func (d *LocalRunner) toDockerComposeService(s *Service) (map[string]interface{}
684684
// create the bind volumes
685685
var createdVolumes []string
686686
for localPath, volume := range s.VolumesMapped {
687+
if volume.HostPath != "" {
688+
volumes[volume.HostPath] = localPath
689+
continue
690+
}
691+
687692
dockerVolumeName := d.createVolumeName(s.Name, volume.Name)
688693

689694
if volume.IsLocal {

playground/manifest.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,9 @@ type Service struct {
450450
}
451451

452452
type VolumeMapped struct {
453-
Name string
454-
IsLocal bool
453+
Name string
454+
IsLocal bool
455+
HostPath string
455456
}
456457

457458
type DependsOnCondition string
@@ -604,6 +605,16 @@ func (s *Service) WithVolume(name, localPath string, isLocalTri ...bool) *Servic
604605
return s
605606
}
606607

608+
func (s *Service) WithHostVolume(hostPath, containerPath string) *Service {
609+
if s.VolumesMapped == nil {
610+
s.VolumesMapped = make(map[string]*VolumeMapped)
611+
}
612+
s.VolumesMapped[containerPath] = &VolumeMapped{
613+
HostPath: hostPath,
614+
}
615+
return s
616+
}
617+
607618
func (s *Service) WithArtifact(localPath, artifactName string) *Service {
608619
if s.FilesMapped == nil {
609620
s.FilesMapped = make(map[string]string)

playground/recipe_yaml.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ type YAMLServiceConfig struct {
116116
}
117117

118118
type YAMLVolumeMappedConfig struct {
119-
Name string `yaml:"name"`
120-
IsLocal bool `yaml:"is_local"`
119+
Name string `yaml:"name"`
120+
IsLocal bool `yaml:"is_local"`
121+
HostPath string `yaml:"host_path"`
121122
}
122123

123124
// YAMLReleaseConfig specifies a GitHub release to download
@@ -481,9 +482,7 @@ func applyServiceOverrides(svc *Service, config *YAMLServiceConfig, root *Compon
481482
applyFilesToService(svc, config.Files)
482483
}
483484
if config.Volumes != nil {
484-
for containerPath, volumeMapping := range config.Volumes {
485-
svc.WithVolume(volumeMapping.Name, containerPath, volumeMapping.IsLocal)
486-
}
485+
applyVolumesToService(svc, config.Volumes)
487486
}
488487
if config.DependsOn != nil {
489488
applyDependsOn(svc, config.DependsOn, root)
@@ -573,7 +572,17 @@ func yamlReleaseToRelease(cfg *YAMLReleaseConfig) *release {
573572
}
574573
}
575574

576-
// applyFilesToService maps files to a service
575+
// applyVolumesToService maps volumes to a service
576+
func applyVolumesToService(svc *Service, volumes map[string]*YAMLVolumeMappedConfig) {
577+
for containerPath, volumeMapping := range volumes {
578+
if volumeMapping.HostPath != "" {
579+
svc.WithHostVolume(volumeMapping.HostPath, containerPath)
580+
} else {
581+
svc.WithVolume(volumeMapping.Name, containerPath, volumeMapping.IsLocal)
582+
}
583+
}
584+
}
585+
577586
func applyFilesToService(svc *Service, files map[string]string) {
578587
for containerPath, fileSource := range files {
579588
var artifactName string
@@ -662,9 +671,7 @@ func createServiceFromConfig(name string, config *YAMLServiceConfig, root *Compo
662671
applyFilesToService(svc, config.Files)
663672
}
664673
if config.Volumes != nil {
665-
for containerPath, volumeMapping := range config.Volumes {
666-
svc.WithVolume(volumeMapping.Name, containerPath, volumeMapping.IsLocal)
667-
}
674+
applyVolumesToService(svc, config.Volumes)
668675
}
669676
if config.DependsOn != nil {
670677
applyDependsOn(svc, config.DependsOn, root)

playground/recipe_yaml_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,22 @@ func TestCreateServiceFromConfig_WithVolumes(t *testing.T) {
417417
require.Equal(t, "myvolume", svc.VolumesMapped["/data"].Name)
418418
}
419419

420+
func TestCreateServiceFromConfig_WithHostPathVolume(t *testing.T) {
421+
config := &YAMLServiceConfig{
422+
Image: "test-image",
423+
Volumes: map[string]*YAMLVolumeMappedConfig{"/var/run/docker.sock": {
424+
HostPath: "/var/run/docker.sock",
425+
}},
426+
}
427+
428+
svc := createServiceFromConfig("my-service", config, nil, "")
429+
430+
require.NotNil(t, svc.VolumesMapped)
431+
require.Equal(t, "/var/run/docker.sock", svc.VolumesMapped["/var/run/docker.sock"].HostPath)
432+
require.Empty(t, svc.VolumesMapped["/var/run/docker.sock"].Name)
433+
require.False(t, svc.VolumesMapped["/var/run/docker.sock"].IsLocal)
434+
}
435+
420436
func TestParseYAMLRecipe(t *testing.T) {
421437
tmpDir, err := os.MkdirTemp("", "recipe-test")
422438
require.NoError(t, err)

0 commit comments

Comments
 (0)