Ver código fonte

Merge pull request #893 from docker/add-view-inspect

Add container inspect view
Guillaume Tardif 5 anos atrás
pai
commit
40e6655c2e

+ 78 - 1
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,
+	}
+}

+ 1 - 14
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"
 }

+ 23 - 11
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() {

+ 1 - 14
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"
 }

+ 0 - 15
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)