Skip to content
This repository was archived by the owner on Jul 18, 2025. It is now read-only.

Commit 4e0989c

Browse files
authored
Merge pull request #721 from glours/inspect_info_running_app_only
Add inspect command to display info of running application only
2 parents cab6001 + 7670989 commit 4e0989c

File tree

126 files changed

+4589
-1710
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

126 files changed

+4589
-1710
lines changed

Gopkg.lock

Lines changed: 20 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ required = ["github.com/wadey/gocovmerge"]
5050

5151
[[override]]
5252
name = "github.com/docker/cli"
53-
revision = "d83cd90464377d4164c8f70248d064b979e5ca98"
53+
revision = "6318939f30e01585b34eb6a68a54b890a8d54eb0"
5454

5555
[[override]]
5656
name = "github.com/deislabs/cnab-go"
@@ -70,7 +70,7 @@ required = ["github.com/wadey/gocovmerge"]
7070

7171
[[override]]
7272
name = "github.com/xeipuuv/gojsonschema"
73-
revision = "93e72a773fade158921402d6a24c819b48aba29d"
73+
version = "v1.2.0"
7474

7575
[[override]]
7676
name = "github.com/docker/go-metrics"
@@ -113,6 +113,10 @@ required = ["github.com/wadey/gocovmerge"]
113113
name = "github.com/opencontainers/runtime-spec"
114114
revision = "29686dbc5559d93fb1ef402eeda3e35c38d75af4"
115115

116+
[[override]]
117+
name = "github.com/Microsoft/hcsshim"
118+
revision = "2226e083fc390003ae5aa8325c3c92789afa0e7a"
119+
116120
[[constraint]]
117121
name = "github.com/spf13/pflag"
118122
branch = "master"
@@ -127,6 +131,10 @@ required = ["github.com/wadey/gocovmerge"]
127131
name = "github.com/jackpal/gateway"
128132
revision = "10816db7ab2f4b71e71dba9420bfa67d5be27b33"
129133

134+
[[constraint]]
135+
name = "github.com/dustin/go-humanize"
136+
version = "1.0.0"
137+
130138
[prune]
131139
non-go = true
132140
unused-packages = true

cmd/cnab-run/inspect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ func inspectAction(instanceName string) error {
2121
}
2222

2323
parameters := packager.ExtractCNABParametersValues(packager.ExtractCNABParameterMapping(app.Parameters()), os.Environ())
24-
return appinspect.Inspect(os.Stdout, app, parameters, imageMap)
24+
return appinspect.ImageInspect(os.Stdout, app, parameters, imageMap)
2525
}

cmd/cnab-run/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var (
1717
"uninstall": uninstallAction,
1818
internal.ActionStatusNameDeprecated: statusAction,
1919
internal.ActionStatusName: statusAction,
20+
internal.ActionStatusJSONName: statusJSONAction,
2021
internal.ActionInspectName: inspectAction,
2122
internal.ActionRenderName: renderAction,
2223
}

cmd/cnab-run/status.go

Lines changed: 182 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,205 @@
11
package main
22

33
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
47
"os"
8+
"sort"
9+
"strings"
10+
"text/tabwriter"
511

612
"github.com/docker/app/internal"
13+
"github.com/docker/cli/cli/command"
714
"github.com/docker/cli/cli/command/stack"
815
"github.com/docker/cli/cli/command/stack/options"
916
"github.com/docker/cli/opts"
17+
"github.com/docker/distribution/reference"
18+
swarmtypes "github.com/docker/docker/api/types/swarm"
19+
"github.com/docker/docker/pkg/stringid"
1020
"github.com/pkg/errors"
1121
)
1222

23+
var (
24+
listColumns = []struct {
25+
header string
26+
value func(s *swarmtypes.Service) string
27+
}{
28+
{"ID", func(s *swarmtypes.Service) string { return stringid.TruncateID(s.ID) }},
29+
{"NAME", func(s *swarmtypes.Service) string { return s.Spec.Name }},
30+
{"MODE", func(s *swarmtypes.Service) string {
31+
if s.Spec.Mode.Replicated != nil {
32+
return "replicated"
33+
}
34+
return "global"
35+
}},
36+
{"REPLICAS", func(s *swarmtypes.Service) string {
37+
if s.Spec.Mode.Replicated != nil {
38+
return fmt.Sprintf("%d/%d", s.ServiceStatus.RunningTasks, s.ServiceStatus.DesiredTasks)
39+
}
40+
return ""
41+
}},
42+
{"IMAGE", func(s *swarmtypes.Service) string {
43+
ref, err := reference.ParseAnyReference(s.Spec.TaskTemplate.ContainerSpec.Image)
44+
if err != nil {
45+
return "N/A"
46+
}
47+
if namedRef, ok := ref.(reference.Named); ok {
48+
return reference.FamiliarName(namedRef)
49+
}
50+
return reference.FamiliarString(ref)
51+
}},
52+
{"PORTS", func(s *swarmtypes.Service) string {
53+
return ports(s.Endpoint.Ports)
54+
}},
55+
}
56+
)
57+
58+
type portRange struct {
59+
pStart uint32
60+
pEnd uint32
61+
tStart uint32
62+
tEnd uint32
63+
protocol swarmtypes.PortConfigProtocol
64+
}
65+
66+
func (pr portRange) String() string {
67+
var (
68+
pub string
69+
tgt string
70+
)
71+
72+
if pr.pEnd > pr.pStart {
73+
pub = fmt.Sprintf("%d-%d", pr.pStart, pr.pEnd)
74+
} else {
75+
pub = fmt.Sprintf("%d", pr.pStart)
76+
}
77+
if pr.tEnd > pr.tStart {
78+
tgt = fmt.Sprintf("%d-%d", pr.tStart, pr.tEnd)
79+
} else {
80+
tgt = fmt.Sprintf("%d", pr.tStart)
81+
}
82+
return fmt.Sprintf("*:%s->%s/%s", pub, tgt, pr.protocol)
83+
}
84+
85+
// Ports formats port configuration. This function is copied et adapted from docker CLI
86+
// see https://github.com/docker/cli/blob/d6edc912ce/cli/command/service/formatter.go#L655
87+
func ports(servicePorts []swarmtypes.PortConfig) string {
88+
if servicePorts == nil {
89+
return ""
90+
}
91+
92+
pr := portRange{}
93+
ports := []string{}
94+
95+
sort.Slice(servicePorts, func(i, j int) bool {
96+
if servicePorts[i].Protocol == servicePorts[j].Protocol {
97+
return servicePorts[i].PublishedPort < servicePorts[j].PublishedPort
98+
}
99+
return servicePorts[i].Protocol < servicePorts[j].Protocol
100+
})
101+
102+
for _, p := range servicePorts {
103+
if p.PublishMode == swarmtypes.PortConfigPublishModeIngress {
104+
prIsRange := pr.tEnd != pr.tStart
105+
tOverlaps := p.TargetPort <= pr.tEnd
106+
107+
// Start a new port-range if:
108+
// - the protocol is different from the current port-range
109+
// - published or target port are not consecutive to the current port-range
110+
// - the current port-range is a _range_, and the target port overlaps with the current range's target-ports
111+
if p.Protocol != pr.protocol || p.PublishedPort-pr.pEnd > 1 || p.TargetPort-pr.tEnd > 1 || prIsRange && tOverlaps {
112+
// start a new port-range, and print the previous port-range (if any)
113+
if pr.pStart > 0 {
114+
ports = append(ports, pr.String())
115+
}
116+
pr = portRange{
117+
pStart: p.PublishedPort,
118+
pEnd: p.PublishedPort,
119+
tStart: p.TargetPort,
120+
tEnd: p.TargetPort,
121+
protocol: p.Protocol,
122+
}
123+
continue
124+
}
125+
pr.pEnd = p.PublishedPort
126+
pr.tEnd = p.TargetPort
127+
}
128+
}
129+
if pr.pStart > 0 {
130+
ports = append(ports, pr.String())
131+
}
132+
return strings.Join(ports, ", ")
133+
}
134+
13135
func statusAction(instanceName string) error {
136+
cli, err := getCli()
137+
if err != nil {
138+
return err
139+
}
140+
services, _ := runningServices(cli, instanceName)
141+
if err := printServices(cli.Out(), services); err != nil {
142+
return err
143+
}
144+
return nil
145+
}
146+
147+
func statusJSONAction(instanceName string) error {
148+
cli, err := getCli()
149+
if err != nil {
150+
return err
151+
}
152+
services, _ := runningServices(cli, instanceName)
153+
js, err := json.MarshalIndent(services, "", " ")
154+
if err != nil {
155+
return err
156+
}
157+
fmt.Fprintln(cli.Out(), string(js))
158+
return nil
159+
}
160+
161+
func getCli() (command.Cli, error) {
14162
cli, err := setupDockerContext()
15163
if err != nil {
16-
return errors.Wrap(err, "unable to restore docker context")
164+
return nil, errors.Wrap(err, "unable to restore docker context")
17165
}
166+
return cli, nil
167+
}
168+
169+
func runningServices(cli command.Cli, instanceName string) ([]swarmtypes.Service, error) {
18170
orchestratorRaw := os.Getenv(internal.DockerStackOrchestratorEnvVar)
19171
orchestrator, err := cli.StackOrchestrator(orchestratorRaw)
20172
if err != nil {
21-
return err
173+
return nil, err
22174
}
23-
return stack.RunServices(cli, getFlagset(orchestrator), orchestrator, options.Services{
24-
Namespace: instanceName,
175+
return stack.GetServices(cli, getFlagset(orchestrator), orchestrator, options.Services{
25176
Filter: opts.NewFilterOpt(),
177+
Namespace: instanceName,
26178
})
27179
}
180+
181+
func printServices(out io.Writer, services []swarmtypes.Service) error {
182+
w := tabwriter.NewWriter(out, 0, 0, 1, ' ', 0)
183+
printHeaders(w)
184+
185+
for _, service := range services {
186+
printValues(w, &service)
187+
}
188+
return w.Flush()
189+
}
190+
191+
func printHeaders(w io.Writer) {
192+
var headers []string
193+
for _, column := range listColumns {
194+
headers = append(headers, column.header)
195+
}
196+
fmt.Fprintln(w, strings.Join(headers, "\t"))
197+
}
198+
199+
func printValues(w io.Writer, service *swarmtypes.Service) {
200+
var values []string
201+
for _, column := range listColumns {
202+
values = append(values, column.value(service))
203+
}
204+
fmt.Fprintln(w, strings.Join(values, "\t"))
205+
}

e2e/testdata/plugin-usage.golden

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Management Commands:
1212
Commands:
1313
build Build an App image from an App definition (.dockerapp)
1414
init Initialize an App definition
15+
inspect Shows status, metadata, parameters and the list of services of a running App
1516
ls List running Apps
1617
pull Pull an App image from a registry
1718
push Push an App image to a registry

0 commit comments

Comments
 (0)