Skip to content

Commit

Permalink
add generation of healthcheck, volumes, bind mount and secrets
Browse files Browse the repository at this point in the history
Signed-off-by: Guillaume Lours <705411+glours@users.noreply.github.com>
  • Loading branch information
glours committed Oct 15, 2024
1 parent 2b727f9 commit fab7feb
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 4 deletions.
35 changes: 34 additions & 1 deletion pkg/compose/compose.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import (
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/client"

"golang.org/x/exp/maps"
)

var stdioToStdout bool
Expand Down Expand Up @@ -166,7 +168,7 @@ func getContainerNameWithoutProject(c moby.Container) string {
}

// projectFromName builds a types.Project based on actual resources with compose labels set
func (s *composeService) projectFromName(containers Containers, projectName string, services ...string) (*types.Project, error) {
func (s *composeService) projectFromName(containers Containers, projectName string, generateMode bool, services ...string) (*types.Project, error) {
project := &types.Project{
Name: projectName,
Services: types.Services{},
Expand All @@ -175,6 +177,11 @@ func (s *composeService) projectFromName(containers Containers, projectName stri
return project, fmt.Errorf("no container found for project %q: %w", projectName, api.ErrNotFound)
}
set := types.Services{}
networks := types.Networks{}
volumes := types.Volumes{}
secrets := types.Secrets{}
configs := types.Configs{}

for _, c := range containers {
serviceLabel, ok := c.Labels[api.ServiceLabel]
if !ok {
Expand All @@ -190,6 +197,13 @@ func (s *composeService) projectFromName(containers Containers, projectName stri

}
service.Scale = increment(service.Scale)
if generateMode {
inspect, err := s.apiClient().ContainerInspect(context.Background(), c.ID)
if err != nil {
continue
}
s.extractComposeConfiguration(service, inspect, volumes, secrets)
}
set[serviceLabel] = service
}
for name, service := range set {
Expand Down Expand Up @@ -217,6 +231,10 @@ func (s *composeService) projectFromName(containers Containers, projectName stri
}
}
project.Services = set
project.Networks = networks
project.Volumes = volumes
project.Secrets = secrets
project.Configs = configs

SERVICES:
for _, qs := range services {
Expand All @@ -235,6 +253,21 @@ SERVICES:
return project, nil
}

func (s *composeService) extractComposeConfiguration(service types.ServiceConfig, inspect moby.ContainerJSON, volumes types.Volumes, secrets types.Secrets) {
service.Environment = types.NewMappingWithEquals(inspect.Config.Env)
if inspect.Config.Healthcheck != nil {
healthConfig := inspect.Config.Healthcheck
service.HealthCheck = s.toComposeHealthCheck(healthConfig)
}
if len(inspect.Mounts) > 0 {
detectedVolumes, volumeConfigs, detectedSecrets, secretsConfigs := s.toComposeVolumes(inspect.Mounts)
service.Volumes = append(service.Volumes, volumeConfigs...)
service.Secrets = append(service.Secrets, secretsConfigs...)
maps.Copy(volumes, detectedVolumes)
maps.Copy(secrets, detectedSecrets)
}
}

func increment(scale *int) *int {
i := 1
if scale != nil {
Expand Down
73 changes: 73 additions & 0 deletions pkg/compose/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@ import (
"context"
"errors"
"fmt"
"strings"
"time"

compose "github.com/compose-spec/compose-go/v2/types"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/mount"
"github.com/docker/docker/api/types/versions"
)

Expand Down Expand Up @@ -97,3 +100,73 @@ func ToSeconds(d *compose.Duration) *int {
s := int(time.Duration(*d).Seconds())
return &s
}

func (s *composeService) toComposeHealthCheck(healthConfig *container.HealthConfig) *compose.HealthCheckConfig {
var healthCheck compose.HealthCheckConfig
healthCheck.Test = healthConfig.Test
if healthConfig.Timeout != 0 {
timeout := compose.Duration(healthConfig.Timeout)
healthCheck.Timeout = &timeout
}
if healthConfig.Interval != 0 {
interval := compose.Duration(healthConfig.Interval)
healthCheck.Interval = &interval
}
if healthConfig.StartPeriod != 0 {
startPeriod := compose.Duration(healthConfig.StartPeriod)
healthCheck.StartPeriod = &startPeriod
}
if healthConfig.StartInterval != 0 {
startInterval := compose.Duration(healthConfig.StartInterval)
healthCheck.StartInterval = &startInterval
}
if healthConfig.Retries != 0 {
retries := uint64(healthConfig.Retries)
healthCheck.Retries = &retries
}
return &healthCheck
}

func (s *composeService) toComposeVolumes(volumes []types.MountPoint) (map[string]compose.VolumeConfig,
[]compose.ServiceVolumeConfig, map[string]compose.SecretConfig, []compose.ServiceSecretConfig) {
volumeConfigs := make(map[string]compose.VolumeConfig)
secretConfigs := make(map[string]compose.SecretConfig)
var serviceVolumeConfigs []compose.ServiceVolumeConfig
var serviceSecretConfigs []compose.ServiceSecretConfig

for _, volume := range volumes {
serviceVC := compose.ServiceVolumeConfig{
Type: string(volume.Type),
Source: volume.Source,
Target: volume.Destination,
ReadOnly: !volume.RW,
}
switch volume.Type {
case mount.TypeVolume:
serviceVC.Source = volume.Name
vol := compose.VolumeConfig{}
if volume.Driver != "local" {
vol.Driver = volume.Driver
vol.Name = volume.Name
}
volumeConfigs[volume.Name] = vol
serviceVolumeConfigs = append(serviceVolumeConfigs, serviceVC)
case mount.TypeBind:
if strings.HasPrefix(volume.Destination, "/run/secrets") {
destination := strings.Split(volume.Destination, "/")
secret := compose.SecretConfig{
Name: destination[len(destination)-1],
File: strings.TrimPrefix(volume.Source, "/host_mnt"),
}
secretConfigs[secret.Name] = secret
serviceSecretConfigs = append(serviceSecretConfigs, compose.ServiceSecretConfig{
Source: secret.Name,
Target: volume.Destination,
})
} else {
serviceVolumeConfigs = append(serviceVolumeConfigs, serviceVC)
}
}
}
return volumeConfigs, serviceVolumeConfigs, secretConfigs, serviceSecretConfigs
}
2 changes: 1 addition & 1 deletion pkg/compose/down.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,7 @@ func (s *composeService) stopAndRemoveContainer(ctx context.Context, container m

func (s *composeService) getProjectWithResources(ctx context.Context, containers Containers, projectName string) (*types.Project, error) {
containers = containers.filter(isNotOneOff)
p, err := s.projectFromName(containers, projectName)
p, err := s.projectFromName(containers, projectName, false)
if err != nil && !api.IsNotFoundError(err) {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/compose/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,5 @@ func (s *composeService) Generate(ctx context.Context, options api.ReverseOption
}
}

return s.projectFromName(containers, options.Project.Name)
return s.projectFromName(containers, options.Project.Name, true)
}
2 changes: 1 addition & 1 deletion pkg/compose/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (s *composeService) start(ctx context.Context, projectName string, options
return err
}

project, err = s.projectFromName(containers, projectName, options.AttachTo...)
project, err = s.projectFromName(containers, projectName, false, options.AttachTo...)
if err != nil {
return err
}
Expand Down

0 comments on commit fab7feb

Please sign in to comment.