diff --git a/cli/cmd/inspect.go b/cli/cmd/inspect.go index 2e9647996..6ce9a0e2c 100644 --- a/cli/cmd/inspect.go +++ b/cli/cmd/inspect.go @@ -20,10 +20,13 @@ import ( "context" "fmt" + "github.com/Azure/go-autorest/autorest/to" + "github.com/compose-spec/compose-go/types" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/docker/compose-cli/api/client" + "github.com/docker/compose-cli/api/containers" "github.com/docker/compose-cli/formatter" ) @@ -52,7 +55,9 @@ func runInspect(ctx context.Context, id string) error { return err } - j, err := formatter.ToStandardJSON(container) + view := getInspectView(container) + + j, err := formatter.ToStandardJSON(view) if err != nil { return err } @@ -60,3 +65,75 @@ func runInspect(ctx context.Context, id string) error { return nil } + +// ContainerInspectView inspect view +type ContainerInspectView struct { + ID string + Status string + Image string + Command string `json:",omitempty"` + HostConfig *containers.HostConfig `json:",omitempty"` + Ports []containers.Port `json:",omitempty"` + Config *containers.RuntimeConfig `json:",omitempty"` + Platform string + Healthcheck *containerInspectHealthcheck `json:",omitempty"` +} + +type containerInspectHealthcheck struct { + // Test is the command to be run to check the health of the container + Test []string `json:",omitempty"` + // Interval is the period in between the checks + Interval *types.Duration `json:",omitempty"` + // Retries is the number of attempts before declaring the container as healthy or unhealthy + Retries *int `json:",omitempty"` + // StartPeriod is the start delay before starting the checks + StartPeriod *types.Duration `json:",omitempty"` + // Timeout is the timeout in between checks + Timeout *types.Duration `json:",omitempty"` +} + +func getInspectView(container containers.Container) ContainerInspectView { + var ( + healthcheck *containerInspectHealthcheck + test []string + retries *int + ports []containers.Port + ) + + if len(container.Ports) > 0 { + ports = container.Ports + } + if !container.Healthcheck.Disable && len(container.Healthcheck.Test) > 0 { + test = container.Healthcheck.Test + if container.Healthcheck.Retries != 0 { + retries = to.IntPtr(container.Healthcheck.Retries) + } + getDurationPtr := func(d types.Duration) *types.Duration { + if d == types.Duration(0) { + return nil + } + return &d + } + + healthcheck = &containerInspectHealthcheck{ + Test: test, + Retries: retries, + Interval: getDurationPtr(container.Healthcheck.Interval), + StartPeriod: getDurationPtr(container.Healthcheck.StartPeriod), + Timeout: getDurationPtr(container.Healthcheck.Timeout), + } + } + + return ContainerInspectView{ + ID: container.ID, + Status: container.Status, + Image: container.Image, + Command: container.Command, + + Config: container.Config, + HostConfig: container.HostConfig, + Ports: ports, + Platform: container.Platform, + Healthcheck: healthcheck, + } +} diff --git a/cli/cmd/testdata/inspect-out-id.golden b/cli/cmd/testdata/inspect-out-id.golden index 517629f4e..1200c98e4 100644 --- a/cli/cmd/testdata/inspect-out-id.golden +++ b/cli/cmd/testdata/inspect-out-id.golden @@ -2,11 +2,6 @@ "ID": "id", "Status": "", "Image": "nginx", - "Command": "", - "CPUTime": 0, - "MemoryUsage": 0, - "PidsCurrent": 0, - "PidsLimit": 0, "HostConfig": { "RestartPolicy": "none", "CPUReservation": 0, @@ -15,13 +10,5 @@ "MemoryLimit": 0, "AutoRemove": false }, - "Platform": "Linux", - "Healthcheck": { - "Disable": false, - "Test": null, - "Interval": "0s", - "Retries": 0, - "StartPeriod": "0s", - "Timeout": "0s" - } + "Platform": "Linux" } diff --git a/tests/aci-e2e/e2e-aci_test.go b/tests/aci-e2e/e2e-aci_test.go index 506939311..d3820dcda 100644 --- a/tests/aci-e2e/e2e-aci_test.go +++ b/tests/aci-e2e/e2e-aci_test.go @@ -17,7 +17,9 @@ package main import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "io/ioutil" @@ -49,6 +51,7 @@ import ( "github.com/docker/compose-cli/aci/convert" "github.com/docker/compose-cli/aci/login" "github.com/docker/compose-cli/api/containers" + "github.com/docker/compose-cli/cli/cmd" "github.com/docker/compose-cli/context/store" "github.com/docker/compose-cli/errdefs" . "github.com/docker/compose-cli/tests/framework" @@ -271,7 +274,7 @@ func TestRunVolume(t *testing.T) { t.Run("inspect", func(t *testing.T) { res := c.RunDockerCmd("inspect", container) - containerInspect, err := ParseContainerInspect(res.Stdout()) + containerInspect, err := parseContainerInspect(res.Stdout()) assert.NilError(t, err) assert.Equal(t, containerInspect.Platform, "Linux") assert.Equal(t, containerInspect.HostConfig.CPULimit, 1.0) @@ -418,7 +421,7 @@ func TestContainerRunAttached(t *testing.T) { inspectRes := c.RunDockerCmd("inspect", container) - containerInspect, err := ParseContainerInspect(inspectRes.Stdout()) + containerInspect, err := parseContainerInspect(inspectRes.Stdout()) assert.NilError(t, err) assert.Equal(t, containerInspect.Platform, "Linux") assert.Equal(t, containerInspect.HostConfig.CPULimit, 0.1) @@ -549,10 +552,10 @@ func TestUpSecretsResources(t *testing.T) { }) res := c.RunDockerCmd("inspect", web1) - web1Inspect, err := ParseContainerInspect(res.Stdout()) + web1Inspect, err := parseContainerInspect(res.Stdout()) assert.NilError(t, err) res = c.RunDockerCmd("inspect", web2) - web2Inspect, err := ParseContainerInspect(res.Stdout()) + web2Inspect, err := parseContainerInspect(res.Stdout()) assert.NilError(t, err) t.Run("read secrets in service 1", func(t *testing.T) { @@ -593,11 +596,11 @@ func TestUpSecretsResources(t *testing.T) { }) t.Run("check healthchecks inspect", func(t *testing.T) { - assert.Equal(t, web1Inspect.Healthcheck.Disable, false) - assert.Equal(t, time.Duration(web1Inspect.Healthcheck.Interval), 5*time.Second) + assert.Assert(t, web1Inspect.Healthcheck != nil) + assert.Equal(t, time.Duration(*web1Inspect.Healthcheck.Interval), 5*time.Second) assert.DeepEqual(t, web1Inspect.Healthcheck.Test, []string{"curl", "-f", "http://localhost:80/healthz"}) - assert.Equal(t, web2Inspect.Healthcheck.Disable, true) + assert.Assert(t, web2Inspect.Healthcheck == nil) }) t.Run("healthcheck restart failed app", func(t *testing.T) { @@ -623,7 +626,7 @@ func TestUpSecretsResources(t *testing.T) { poll.WaitOn(t, checkLogsReset, poll.WithDelay(5*time.Second), poll.WithTimeout(90*time.Second)) res := c.RunDockerCmd("inspect", web1) - web1Inspect, err = ParseContainerInspect(res.Stdout()) + web1Inspect, err = parseContainerInspect(res.Stdout()) assert.Equal(t, web1Inspect.Status, "Running") }) } @@ -697,7 +700,7 @@ func TestUpUpdate(t *testing.T) { res = c.RunDockerCmd("inspect", serverContainer) - containerInspect, err := ParseContainerInspect(res.Stdout()) + containerInspect, err := parseContainerInspect(res.Stdout()) assert.NilError(t, err) assert.Assert(t, is.Len(containerInspect.Ports, 1)) endpoint := fmt.Sprintf("http://%s:%d", containerInspect.Ports[0].HostIP, containerInspect.Ports[0].HostPort) @@ -781,7 +784,7 @@ func TestUpUpdate(t *testing.T) { for _, cName := range []string{serverContainer, wordsContainer} { res = c.RunDockerCmd("inspect", cName) - containerInspect, err := ParseContainerInspect(res.Stdout()) + containerInspect, err := parseContainerInspect(res.Stdout()) assert.NilError(t, err) assert.Assert(t, is.Len(containerInspect.Ports, 1)) endpoint := fmt.Sprintf("http://%s:%d", containerInspect.Ports[0].HostIP, containerInspect.Ports[0].HostPort) @@ -949,7 +952,7 @@ func getContainerName(stdout string) string { func waitForStatus(t *testing.T, c *E2eCLI, containerID string, statuses ...string) { checkStopped := func(logt poll.LogT) poll.Result { res := c.RunDockerCmd("inspect", containerID) - containerInspect, err := ParseContainerInspect(res.Stdout()) + containerInspect, err := parseContainerInspect(res.Stdout()) assert.NilError(t, err) for _, status := range statuses { if containerInspect.Status == status { @@ -962,6 +965,15 @@ func waitForStatus(t *testing.T, c *E2eCLI, containerID string, statuses ...stri poll.WaitOn(t, checkStopped, poll.WithDelay(5*time.Second), poll.WithTimeout(90*time.Second)) } +func parseContainerInspect(stdout string) (*cmd.ContainerInspectView, error) { + var res cmd.ContainerInspectView + rdr := bytes.NewReader([]byte(stdout)) + if err := json.NewDecoder(rdr).Decode(&res); err != nil { + return nil, err + } + return &res, nil +} + func waitWithTimeout(blockingCall func(), timeout time.Duration) error { c := make(chan struct{}) go func() { diff --git a/tests/e2e/testdata/inspect-id.golden b/tests/e2e/testdata/inspect-id.golden index 517629f4e..1200c98e4 100644 --- a/tests/e2e/testdata/inspect-id.golden +++ b/tests/e2e/testdata/inspect-id.golden @@ -2,11 +2,6 @@ "ID": "id", "Status": "", "Image": "nginx", - "Command": "", - "CPUTime": 0, - "MemoryUsage": 0, - "PidsCurrent": 0, - "PidsLimit": 0, "HostConfig": { "RestartPolicy": "none", "CPUReservation": 0, @@ -15,13 +10,5 @@ "MemoryLimit": 0, "AutoRemove": false }, - "Platform": "Linux", - "Healthcheck": { - "Disable": false, - "Test": null, - "Interval": "0s", - "Retries": 0, - "StartPeriod": "0s", - "Timeout": "0s" - } + "Platform": "Linux" } diff --git a/tests/framework/e2e.go b/tests/framework/e2e.go index ee500ca6f..edf450c0c 100644 --- a/tests/framework/e2e.go +++ b/tests/framework/e2e.go @@ -17,8 +17,6 @@ package framework import ( - "bytes" - "encoding/json" "errors" "fmt" "io/ioutil" @@ -35,8 +33,6 @@ import ( is "gotest.tools/v3/assert/cmp" "gotest.tools/v3/icmd" "gotest.tools/v3/poll" - - "github.com/docker/compose-cli/api/containers" ) var ( @@ -196,17 +192,6 @@ func GoldenFile(name string) string { return name + ".golden" } -// ParseContainerInspect parses the output of a `docker inspect` command for a -// container -func ParseContainerInspect(stdout string) (*containers.Container, error) { - var res containers.Container - rdr := bytes.NewReader([]byte(stdout)) - if err := json.NewDecoder(rdr).Decode(&res); err != nil { - return nil, err - } - return &res, nil -} - // HTTPGetWithRetry performs an HTTP GET on an `endpoint`, using retryDelay also as a request timeout. // In the case of an error or the response status is not the expeted one, it retries the same request, // returning the response body as a string (empty if we could not reach it)