Forráskód Böngészése

Add Healthchecks to ACI

Signed-off-by: Ulysses Souza <[email protected]>
Ulysses Souza 5 éve
szülő
commit
f6509ac814

+ 9 - 0
aci/convert/container.go

@@ -40,6 +40,7 @@ func ContainerToComposeProject(r containers.ContainerConfig) (types.Project, err
 		return types.Project{}, err
 	}
 
+	retries := uint64(r.Healthcheck.Retries)
 	project := types.Project{
 		Name: r.ID,
 		Services: []types.ServiceConfig{
@@ -52,6 +53,14 @@ func ContainerToComposeProject(r containers.ContainerConfig) (types.Project, err
 				Volumes:     serviceConfigVolumes,
 				DomainName:  r.DomainName,
 				Environment: toComposeEnvs(r.Environment),
+				HealthCheck: &types.HealthCheckConfig{
+					Test:        r.Healthcheck.Test,
+					Timeout:     &r.Healthcheck.Timeout,
+					Interval:    &r.Healthcheck.Interval,
+					Retries:     &retries,
+					StartPeriod: &r.Healthcheck.StartPeriod,
+					Disable:     r.Healthcheck.Disable,
+				},
 				Deploy: &types.DeployConfig{
 					Resources: types.Resources{
 						Reservations: &types.Resource{

+ 72 - 7
aci/convert/convert.go

@@ -23,6 +23,7 @@ import (
 	"os"
 	"strconv"
 	"strings"
+	"time"
 
 	"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
 	"github.com/Azure/go-autorest/autorest/to"
@@ -68,7 +69,7 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
 		return containerinstance.ContainerGroup{}, err
 	}
 
-	var containers []containerinstance.Container
+	var ctnrs []containerinstance.Container
 	restartPolicy, err := project.getRestartPolicy()
 	if err != nil {
 		return containerinstance.ContainerGroup{}, err
@@ -78,7 +79,7 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
 		Location: &aciContext.Location,
 		ContainerGroupProperties: &containerinstance.ContainerGroupProperties{
 			OsType:                   containerinstance.Linux,
-			Containers:               &containers,
+			Containers:               &ctnrs,
 			Volumes:                  volumes,
 			ImageRegistryCredentials: &registryCreds,
 			RestartPolicy:            restartPolicy,
@@ -110,7 +111,7 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
 			dnsLabelName = serviceDomainName
 		}
 
-		containers = append(containers, containerDefinition)
+		ctnrs = append(ctnrs, containerDefinition)
 	}
 	if len(groupPorts) > 0 {
 		groupDefinition.ContainerGroupProperties.IPAddress = &containerinstance.IPAddress{
@@ -119,15 +120,23 @@ func ToContainerGroup(ctx context.Context, aciContext store.AciContext, p types.
 			DNSNameLabel: dnsLabelName,
 		}
 	}
-	if len(containers) > 1 {
-		dnsSideCar := getDNSSidecar(containers)
-		containers = append(containers, dnsSideCar)
+	if len(ctnrs) > 1 {
+		dnsSideCar := getDNSSidecar(ctnrs)
+		ctnrs = append(ctnrs, dnsSideCar)
 	}
-	groupDefinition.ContainerGroupProperties.Containers = &containers
+	groupDefinition.ContainerGroupProperties.Containers = &ctnrs
 
 	return groupDefinition, nil
 }
 
+func durationToSeconds(d *types.Duration) *int32 {
+	if d == nil {
+		return nil
+	}
+	v := int32(time.Duration(*d).Seconds())
+	return &v
+}
+
 func getDNSSidecar(containers []containerinstance.Container) containerinstance.Container {
 	names := []string{"/hosts"}
 	for _, container := range containers {
@@ -181,6 +190,7 @@ func (s serviceConfigAciHelper) getAciContainer(volumesCache map[string]bool) (c
 			EnvironmentVariables: getEnvVariables(s.Environment),
 			Resources:            resource,
 			VolumeMounts:         volumes,
+			LivenessProbe:        s.getLivenessProbe(),
 		},
 	}, nil
 }
@@ -237,6 +247,35 @@ func (s serviceConfigAciHelper) getResourceRequestsLimits() (*containerinstance.
 	return &resources, nil
 }
 
+func (s serviceConfigAciHelper) getLivenessProbe() *containerinstance.ContainerProbe {
+	if s.HealthCheck != nil && !s.HealthCheck.Disable && len(s.HealthCheck.Test) > 0 {
+		testArray := s.HealthCheck.Test
+		switch s.HealthCheck.Test[0] {
+		case "NONE", "CMD", "CMD-SHELL":
+			testArray = s.HealthCheck.Test[1:]
+		}
+		if len(testArray) == 0 {
+			return nil
+		}
+
+		var retries *int32
+		if s.HealthCheck.Retries != nil {
+			retries = to.Int32Ptr(int32(*s.HealthCheck.Retries))
+		}
+		return &containerinstance.ContainerProbe{
+			Exec: &containerinstance.ContainerExec{
+				Command: to.StringSlicePtr(testArray),
+			},
+			InitialDelaySeconds: durationToSeconds(s.HealthCheck.StartPeriod),
+			PeriodSeconds:       durationToSeconds(s.HealthCheck.Interval),
+			FailureThreshold:    retries,
+			SuccessThreshold:    retries,
+			TimeoutSeconds:      durationToSeconds(s.HealthCheck.Timeout),
+		}
+	}
+	return nil
+}
+
 func getEnvVariables(composeEnv types.MappingWithEquals) *[]containerinstance.EnvironmentVariable {
 	result := []containerinstance.EnvironmentVariable{}
 	for key, value := range composeEnv {
@@ -310,6 +349,31 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
 		FQDN: fqdn(cg, region),
 		Env:  envVars,
 	}
+
+	var healthcheck = containers.Healthcheck{
+		Disable: true,
+	}
+	if cc.LivenessProbe != nil &&
+		cc.LivenessProbe.Exec != nil &&
+		cc.LivenessProbe.Exec.Command != nil {
+		if len(*cc.LivenessProbe.Exec.Command) > 0 {
+			healthcheck.Disable = false
+			healthcheck.Test = *cc.LivenessProbe.Exec.Command
+			if cc.LivenessProbe.PeriodSeconds != nil {
+				healthcheck.Interval = types.Duration(int64(*cc.LivenessProbe.PeriodSeconds) * int64(time.Second))
+			}
+			if cc.LivenessProbe.SuccessThreshold != nil {
+				healthcheck.Retries = int(*cc.LivenessProbe.SuccessThreshold)
+			}
+			if cc.LivenessProbe.TimeoutSeconds != nil {
+				healthcheck.Timeout = types.Duration(int64(*cc.LivenessProbe.TimeoutSeconds) * int64(time.Second))
+			}
+			if cc.LivenessProbe.InitialDelaySeconds != nil {
+				healthcheck.StartPeriod = types.Duration(int64(*cc.LivenessProbe.InitialDelaySeconds) * int64(time.Second))
+			}
+		}
+	}
+
 	c := containers.Container{
 		ID:          containerID,
 		Status:      status,
@@ -323,6 +387,7 @@ func ContainerGroupToContainer(containerID string, cg containerinstance.Containe
 		Platform:    platform,
 		Config:      config,
 		HostConfig:  hostConfig,
+		Healthcheck: healthcheck,
 	}
 
 	return c

+ 76 - 0
aci/convert/convert_test.go

@@ -20,6 +20,7 @@ import (
 	"context"
 	"os"
 	"testing"
+	"time"
 
 	"github.com/Azure/azure-sdk-for-go/services/containerinstance/mgmt/2018-10-01/containerinstance"
 	"github.com/Azure/go-autorest/autorest/to"
@@ -88,6 +89,19 @@ func TestContainerGroupToContainer(t *testing.T) {
 					MemoryInGB: to.Float64Ptr(0.1),
 				},
 			},
+			LivenessProbe: &containerinstance.ContainerProbe{
+				Exec: &containerinstance.ContainerExec{
+					Command: to.StringSlicePtr([]string{
+						"my",
+						"command",
+						"--option",
+					}),
+				},
+				PeriodSeconds:       to.Int32Ptr(10),
+				SuccessThreshold:    to.Int32Ptr(3),
+				InitialDelaySeconds: to.Int32Ptr(2),
+				TimeoutSeconds:      to.Int32Ptr(1),
+			},
 		},
 	}
 
@@ -113,12 +127,74 @@ func TestContainerGroupToContainer(t *testing.T) {
 			MemoryReservation: gbToBytes(0.1),
 			RestartPolicy:     "any",
 		},
+		Healthcheck: containers.Healthcheck{
+			Disable: false,
+			Test: []string{
+				"my",
+				"command",
+				"--option",
+			},
+			Interval:    types.Duration(10 * time.Second),
+			Retries:     3,
+			StartPeriod: types.Duration(2 * time.Second),
+			Timeout:     types.Duration(time.Second),
+		},
 	}
 
 	container := ContainerGroupToContainer("myContainerID", myContainerGroup, myContainer, "eastus")
 	assert.DeepEqual(t, container, expectedContainer)
 }
 
+func TestHealthcheckTranslation(t *testing.T) {
+	test := []string{
+		"my",
+		"command",
+		"--option",
+	}
+	interval := types.Duration(10 * time.Second)
+	retries := uint64(42)
+	startPeriod := types.Duration(2 * time.Second)
+	timeout := types.Duration(3 * time.Second)
+	project := types.Project{
+		Services: []types.ServiceConfig{
+			{
+				Name:  "service1",
+				Image: "image1",
+				HealthCheck: &types.HealthCheckConfig{
+					Test:        test,
+					Timeout:     &timeout,
+					Interval:    &interval,
+					Retries:     &retries,
+					StartPeriod: &startPeriod,
+					Disable:     false,
+				},
+			},
+		},
+	}
+
+	testHealthcheckTestPrefixRemoval := func(test []string, shellPreffix ...string) {
+		project.Services[0].HealthCheck.Test = append(shellPreffix, test...)
+		group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
+		assert.NilError(t, err)
+		assert.DeepEqual(t, (*group.Containers)[0].LivenessProbe.Exec.Command, to.StringSlicePtr(test))
+		assert.Equal(t, *(*group.Containers)[0].LivenessProbe.PeriodSeconds, int32(10))
+		assert.Equal(t, *(*group.Containers)[0].LivenessProbe.SuccessThreshold, int32(42))
+		assert.Equal(t, *(*group.Containers)[0].LivenessProbe.FailureThreshold, int32(42))
+		assert.Equal(t, *(*group.Containers)[0].LivenessProbe.InitialDelaySeconds, int32(2))
+		assert.Equal(t, *(*group.Containers)[0].LivenessProbe.TimeoutSeconds, int32(3))
+	}
+
+	testHealthcheckTestPrefixRemoval(test)
+	testHealthcheckTestPrefixRemoval(test, "NONE")
+	testHealthcheckTestPrefixRemoval(test, "CMD")
+	testHealthcheckTestPrefixRemoval(test, "CMD-SHELL")
+
+	project.Services[0].HealthCheck.Disable = true
+	group, err := ToContainerGroup(context.TODO(), convertCtx, project, mockStorageHelper)
+	assert.NilError(t, err)
+	assert.Assert(t, (*group.Containers)[0].LivenessProbe == nil)
+}
+
 func TestContainerGroupToServiceStatus(t *testing.T) {
 	myContainerGroup := containerinstance.ContainerGroup{
 		ContainerGroupProperties: &containerinstance.ContainerGroupProperties{

+ 21 - 0
api/containers/api.go

@@ -20,6 +20,8 @@ import (
 	"context"
 	"io"
 
+	"github.com/compose-spec/compose-go/types"
+
 	"github.com/docker/compose-cli/formatter"
 )
 
@@ -54,6 +56,7 @@ type Container struct {
 	HostConfig  *HostConfig    `json:",omitempty"`
 	Ports       []Port         `json:",omitempty"`
 	Platform    string
+	Healthcheck Healthcheck
 }
 
 // RuntimeConfig config of a created container
@@ -112,6 +115,24 @@ type ContainerConfig struct {
 	DomainName string
 	// AutoRemove sets the container to be removed automatically when stopped
 	AutoRemove bool
+	// Healthcheck contains the command and interval of the checks
+	Healthcheck Healthcheck
+}
+
+// Healthcheck defines the configuration of a healthcheck
+type Healthcheck struct {
+	// Disable disables the check
+	Disable bool
+	// Test is the command to be run to check the health of the container
+	Test []string
+	// Interval is the period in between the checks
+	Interval types.Duration
+	// Retries is the number of attempts before declaring the container as healthy or unhealthy
+	Retries int
+	// StartPeriod is the start delay before starting the checks
+	StartPeriod types.Duration
+	// Timeout is the timeout in between checks
+	Timeout types.Duration
 }
 
 // ExecRequest contaiens configuration about an exec request

+ 7 - 0
cli/cmd/run/run.go

@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"time"
 
 	"github.com/containerd/console"
 	"github.com/spf13/cobra"
@@ -59,6 +60,12 @@ func Command(contextType string) *cobra.Command {
 	cmd.Flags().StringArrayVar(&opts.EnvironmentFiles, "env-file", []string{}, "Path to environment files to be translated as environment variables")
 	cmd.Flags().StringVarP(&opts.RestartPolicyCondition, "restart", "", containers.RestartPolicyRunNo, "Restart policy to apply when a container exits (no|always|on-failure)")
 	cmd.Flags().BoolVar(&opts.Rm, "rm", false, "Automatically remove the container when it exits")
+	cmd.Flags().StringVar(&opts.HealthCmd, "health-cmd", "", "Command to run to check health")
+	cmd.Flags().DurationVar(&opts.HealthInterval, "health-interval", time.Duration(0), "Time between running the check (ms|s|m|h) (default 0s)")
+	cmd.Flags().IntVar(&opts.HealthRetries, "health-retries", 10, "Consecutive failures needed to report unhealthy")
+	cmd.Flags().DurationVar(&opts.HealthStartPeriod, "health-start-period", time.Duration(0), "Start period for the container to initialize before starting "+
+		"health-retries countdown (ms|s|m|h) (default 0s)")
+	cmd.Flags().DurationVar(&opts.HealthTimeout, "health-timeout", time.Duration(0), "Maximum time to allow one check to run (ms|s|m|h) (default 0s)")
 
 	if contextType == store.AciContextType {
 		cmd.Flags().StringVar(&opts.DomainName, "domainname", "", "Container NIS domain name")

+ 16 - 11
cli/cmd/run/testdata/run-help.golden

@@ -4,14 +4,19 @@ Usage:
   run [flags]
 
 Flags:
-      --cpus float             Number of CPUs (default 1)
-  -d, --detach                 Run container in background and print container ID
-      --domainname string      Container NIS domain name
-  -e, --env stringArray        Set environment variables
-      --env-file stringArray   Path to environment files to be translated as environment variables
-  -l, --label stringArray      Set meta data on a container
-  -m, --memory bytes           Memory limit
-      --name string            Assign a name to the container
-  -p, --publish stringArray    Publish a container's port(s). [HOST_PORT:]CONTAINER_PORT
-      --restart string         Restart policy to apply when a container exits (no|always|on-failure) (default "no")
-  -v, --volume stringArray     Volume. Ex: storageaccount/my_share[:/absolute/path/to/target][:ro]
+      --cpus float                     Number of CPUs (default 1)
+  -d, --detach                         Run container in background and print container ID
+      --domainname string              Container NIS domain name
+  -e, --env stringArray                Set environment variables
+      --env-file stringArray           Path to environment files to be translated as environment variables
+      --health-cmd string              Command to run to check health
+      --health-interval duration       Time between running the check (ms|s|m|h) (default 0s)
+      --health-retries int             Consecutive failures needed to report unhealthy (default 10)
+      --health-start-period duration   Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s)
+      --health-timeout duration        Maximum time to allow one check to run (ms|s|m|h) (default 0s)
+  -l, --label stringArray              Set meta data on a container
+  -m, --memory bytes                   Memory limit
+      --name string                    Assign a name to the container
+  -p, --publish stringArray            Publish a container's port(s). [HOST_PORT:]CONTAINER_PORT
+      --restart string                 Restart policy to apply when a container exits (no|always|on-failure) (default "no")
+  -v, --volume stringArray             Volume. Ex: storageaccount/my_share[:/absolute/path/to/target][:ro]

+ 9 - 1
cli/cmd/testdata/inspect-out-id.golden

@@ -15,5 +15,13 @@
         "MemoryLimit": 0,
         "AutoRemove": false
     },
-    "Platform": "Linux"
+    "Platform": "Linux",
+    "Healthcheck": {
+        "Disable": false,
+        "Test": null,
+        "Interval": "0s",
+        "Retries": 0,
+        "StartPeriod": "0s",
+        "Timeout": "0s"
+    }
 }

+ 19 - 0
cli/options/run/opts.go

@@ -20,7 +20,9 @@ import (
 	"fmt"
 	"strconv"
 	"strings"
+	"time"
 
+	"github.com/compose-spec/compose-go/types"
 	"github.com/docker/cli/opts"
 	"github.com/docker/docker/pkg/namesgenerator"
 	"github.com/docker/go-connections/nat"
@@ -44,6 +46,11 @@ type Opts struct {
 	RestartPolicyCondition string
 	DomainName             string
 	Rm                     bool
+	HealthCmd              string
+	HealthInterval         time.Duration
+	HealthRetries          int
+	HealthStartPeriod      time.Duration
+	HealthTimeout          time.Duration
 }
 
 // ToContainerConfig convert run options to a container configuration
@@ -76,6 +83,13 @@ func (r *Opts) ToContainerConfig(image string) (containers.ContainerConfig, erro
 		envVars = append(envVars, vars...)
 	}
 
+	var healthCmd []string
+	var healthInterval types.Duration
+	if len(r.HealthCmd) > 0 {
+		healthCmd = strings.Split(r.HealthCmd, " ")
+		healthInterval = types.Duration(r.HealthInterval)
+	}
+
 	return containers.ContainerConfig{
 		ID:                     r.Name,
 		Image:                  image,
@@ -89,6 +103,11 @@ func (r *Opts) ToContainerConfig(image string) (containers.ContainerConfig, erro
 		RestartPolicyCondition: restartPolicy,
 		DomainName:             r.DomainName,
 		AutoRemove:             r.Rm,
+		Healthcheck: containers.Healthcheck{
+			Disable:  len(healthCmd) == 0,
+			Test:     healthCmd,
+			Interval: healthInterval,
+		},
 	}, nil
 }
 

+ 19 - 1
docs/aci-compose-features.md

@@ -47,7 +47,7 @@ __Legend:__
 | service.external_links         | x |
 | service.extra_hosts            | x |
 | service.group_add              | x |
-| service.healthcheck            | n |
+| service.healthcheck            | ✓ | 
 | service.hostname               | x |
 | service.image                  | ✓ |  Private images will be accessible if the user is logged into the corresponding registry at deploy time. Users will be automatically logged in to Azure Container Registry using their Azure login if possible.
 | service.isolation              | x |
@@ -209,3 +209,21 @@ services:
 
 In this example, the db container will be allocated 2 CPUs and 2G of memory. It will be allowed to use up to 3 CPUs and 3G of memory, using some of the resources allocated to the web container.
 The web container will have its limits set to the same values as reservations, by default.
+
+## Healthchecks
+
+Healthchecks can be described in the `healthcheck` section in the service. It translates to `LivenessProbe` in ACI. By that, the container is restarted if it becomes unhealthy.
+
+```yaml
+services:
+  web:
+    image: nginx
+    healthcheck:
+      test: ["CMD", "curl", "-f", "http://localhost:80"]
+      interval: 30s
+      timeout: 10s
+      retries: 3
+      start_period: 40s
+```
+
+**Note:** that the `test` command can be a `string` or an array starting or not by `NONE`, `CMD`, `CMD-SHELL`. In the ACI implementation, these prefixes are ignored.

+ 1 - 1
go.mod

@@ -22,7 +22,7 @@ require (
 	github.com/aws/aws-sdk-go v1.35.15
 	github.com/awslabs/goformation/v4 v4.15.3
 	github.com/buger/goterm v0.0.0-20200322175922-2f3e71b85129
-	github.com/compose-spec/compose-go v0.0.0-20201005072614-3b6106793209
+	github.com/compose-spec/compose-go v0.0.0-20201104130931-5afecaa4cb35
 	github.com/containerd/console v1.0.1
 	github.com/containerd/containerd v1.3.5 // indirect
 	github.com/docker/cli v0.0.0-20200528204125-dd360c7c0de8

+ 3 - 2
go.sum

@@ -122,8 +122,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/compose-spec/compose-go v0.0.0-20201005072614-3b6106793209 h1:PLZiS7hjkiAqZYBRAEq3tbGlhCh6/R14dO1ahwbEIBg=
-github.com/compose-spec/compose-go v0.0.0-20201005072614-3b6106793209/go.mod h1:rNXXqhdClEljsNb6QDIOqTQaRfigwTgGZZM6Zpr3LeY=
+github.com/compose-spec/compose-go v0.0.0-20201104130931-5afecaa4cb35 h1:HLxSiPmzCkBi3mGgxHQGBi3vxUuzT72Q9xjG49hkvSA=
+github.com/compose-spec/compose-go v0.0.0-20201104130931-5afecaa4cb35/go.mod h1:cBdHyUvAothdUpqXANCfTHU7cEqsXRvSiLxjhOTuwvc=
 github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f h1:tSNMc+rJDfmYntojat8lljbt1mgKNpTxUZJsSzJ9Y1s=
 github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko=
 github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw=
@@ -516,6 +516,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMc
 github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
+github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56 h1:yhqBHs09SmmUoNOHc9jgK4a60T3XFRtPAkYxVnqgY50=
 github.com/xeipuuv/gojsonschema v0.0.0-20181112162635-ac52e6811b56/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs=
 github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
 github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 366 - 268
protos/containers/v1/containers.pb.go


+ 8 - 0
protos/containers/v1/containers.proto

@@ -51,6 +51,7 @@ message Container {
 	repeated Port ports = 11;
 	string platform = 13;
 	HostConfig host_config = 15;
+	Healthcheck healthcheck = 16;
 }
 
 message HostConfig {
@@ -62,6 +63,12 @@ message HostConfig {
 	bool auto_remove = 6;
 }
 
+message Healthcheck {
+	bool disable = 1;
+	repeated string test = 2;
+	int64 interval = 3;
+}
+
 message InspectRequest {
 	string id = 1;
 }
@@ -113,6 +120,7 @@ message RunRequest {
 	repeated string command = 9;
 	repeated string environment = 10;
 	bool auto_remove = 11;
+	Healthcheck  healthcheck = 12;
 }
 
 message RunResponse {

+ 12 - 0
server/proxy/containers.go

@@ -20,6 +20,8 @@ import (
 	"context"
 	"errors"
 
+	"github.com/compose-spec/compose-go/types"
+
 	"github.com/docker/compose-cli/api/containers"
 	"github.com/docker/compose-cli/formatter"
 	containersv1 "github.com/docker/compose-cli/protos/containers/v1"
@@ -141,6 +143,11 @@ func toGrpcContainer(c containers.Container) *containersv1.Container {
 			RestartPolicy:     c.HostConfig.RestartPolicy,
 			AutoRemove:        c.HostConfig.AutoRemove,
 		},
+		Healthcheck: &containersv1.Healthcheck{
+			Disable:  c.Healthcheck.Disable,
+			Test:     c.Healthcheck.Test,
+			Interval: int64(c.Healthcheck.Interval),
+		},
 	}
 }
 
@@ -167,5 +174,10 @@ func grpcContainerToContainerConfig(request *containersv1.RunRequest) containers
 		RestartPolicyCondition: request.RestartPolicyCondition,
 		Environment:            request.Environment,
 		AutoRemove:             request.AutoRemove,
+		Healthcheck: containers.Healthcheck{
+			Disable:  request.GetHealthcheck().GetDisable(),
+			Test:     request.GetHealthcheck().GetTest(),
+			Interval: types.Duration(request.GetHealthcheck().GetInterval()),
+		},
 	}
 }

+ 9 - 1
tests/e2e/testdata/inspect-id.golden

@@ -15,5 +15,13 @@
         "MemoryLimit": 0,
         "AutoRemove": false
     },
-    "Platform": "Linux"
+    "Platform": "Linux",
+    "Healthcheck": {
+        "Disable": false,
+        "Test": null,
+        "Interval": "0s",
+        "Retries": 0,
+        "StartPeriod": "0s",
+        "Timeout": "0s"
+    }
 }

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott