Skip to content

Commit 25c8701

Browse files
authored
stack status cmd - add columns for image build date and VCS reference (#2057)
When dealing with snapshot builds that are constantly updated, it's difficult to know what build of a service is really running. When viewing historic build logs from CI this information is important to know. This adds information about the service's image to the output of `elastic-package stack status`. The new columns in the output are IMAGE BUILD DATE and VCS REF. The data is read from http://label-schema.org/rc1/ labels. It uses the org.label-schema.build-date and org.label-schema.vcs-ref labels.
1 parent dfcb540 commit 25c8701

File tree

5 files changed

+50
-13
lines changed

5 files changed

+50
-13
lines changed

cmd/stack.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package cmd
77
import (
88
"fmt"
99
"strings"
10+
"time"
1011

1112
"github.com/olekukonko/tablewriter"
1213
"github.com/olekukonko/tablewriter/renderer"
@@ -385,9 +386,31 @@ func printStatus(cmd *cobra.Command, servicesStatus []stack.ServiceStatus) {
385386
tablewriter.WithRenderer(renderer.NewColorized(config)),
386387
tablewriter.WithConfig(defaultTableConfig),
387388
)
388-
table.Header("Service", "Version", "Status")
389+
table.Header("Service", "Version", "Status", "Image Build Date", "VCS Ref")
389390
for _, service := range servicesStatus {
390-
table.Append(service.Name, service.Version, service.Status)
391+
var buildDate, vcsRef string
392+
if service.Labels != nil {
393+
buildDate = formatTime(service.Labels.BuildDate)
394+
vcsRef = truncate(service.Labels.VCSRef, 10)
395+
}
396+
table.Append(service.Name, service.Version, service.Status, buildDate, vcsRef)
391397
}
392398
table.Render()
393399
}
400+
401+
// formatTime returns the given RFC3339 time formated as 2006-01-02T15:04Z.
402+
// If the value is not in RFC3339 format, then it is returned as-is.
403+
func formatTime(maybeRFC3339Time string) string {
404+
if t, err := time.Parse(time.RFC3339, maybeRFC3339Time); err == nil {
405+
return t.UTC().Format("2006-01-02T15:04Z")
406+
}
407+
return maybeRFC3339Time
408+
}
409+
410+
// truncate truncates text if it is longer than maxLength.
411+
func truncate(text string, maxLength int) string {
412+
if len(text) > maxLength {
413+
return text[:maxLength]
414+
}
415+
return text
416+
}

internal/docker/docker.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ type ConfigLabels struct {
4949
ComposeProject string `json:"com.docker.compose.project"`
5050
ComposeService string `json:"com.docker.compose.service"`
5151
ComposeVersion string `json:"com.docker.compose.version"`
52+
53+
// http://label-schema.org/rc1/ Labels
54+
BuildDate string `json:"org.label-schema.build-date,omitempty"` // This label contains the Date/Time the image was built. The value SHOULD be formatted according to RFC 3339.
55+
VCSRef string `json:"org.label-schema.vcs-ref,omitempty"` // Identifier for the version of the source code from which this image was built. For example if the version control system is git this is the SHA.
5256
}
5357

5458
// String function dumps string representation of the container description.

internal/stack/compose.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type ServiceStatus struct {
1818
Name string
1919
Status string
2020
Version string
21+
Labels *docker.ConfigLabels // Container labels.
2122
}
2223

2324
const readyServicesSuffix = "is_ready"
@@ -234,6 +235,7 @@ func newServiceStatus(description *docker.ContainerDescription) (*ServiceStatus,
234235
Name: description.Config.Labels.ComposeService,
235236
Status: description.State.Status,
236237
Version: getVersionFromDockerImage(description.Config.Image),
238+
Labels: &description.Config.Labels,
237239
}
238240
if description.State.Status == "running" {
239241
healthStatus := "unknown health"

internal/stack/compose_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ func TestNewServiceStatus(t *testing.T) {
7878
Name: "myservice",
7979
Status: "running (healthy)",
8080
Version: "1.42.0",
81+
Labels: &docker.ConfigLabels{ComposeService: "myservice"},
8182
},
8283
},
8384
{
@@ -112,6 +113,7 @@ func TestNewServiceStatus(t *testing.T) {
112113
Name: "myservice",
113114
Status: "exited (128)",
114115
Version: "1.42.0",
116+
Labels: &docker.ConfigLabels{ComposeService: "myservice"},
115117
},
116118
},
117119
{
@@ -155,6 +157,7 @@ func TestNewServiceStatus(t *testing.T) {
155157
Name: "myservice",
156158
Status: "running (starting)",
157159
Version: "1.42.0",
160+
Labels: &docker.ConfigLabels{ComposeService: "myservice"},
158161
},
159162
},
160163
}

scripts/test-stack-command.sh

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ default_version() {
5050

5151
clean_status_output() {
5252
local output_file="$1"
53-
cat "${output_file}" | grep "" | tr -d ' '
53+
# This removes the 'IMAGE BUILD DATE" and 'VCS REF' columns and
54+
# removes the whitespace between columns.
55+
grep "" "${output_file}" \
56+
| sed 's/│/|/g' \
57+
| cut -d '|' -f 1-4,7- \
58+
| tr -d ' '
5459
}
5560

5661
trap cleanup EXIT
@@ -140,20 +145,20 @@ curl --cacert "${ELASTIC_PACKAGE_CA_CERT}" -f "${ELASTIC_PACKAGE_KIBANA_HOST}/lo
140145
# Check status with running services
141146
cat <<EOF > "${OUTPUT_PATH_STATUS}/expected_running.txt"
142147
Status of Elastic stack services:
143-
╭──────────────────┬─────────┬───────────────────╮
144-
│ SERVICE │ VERSION │ STATUS │
145-
├──────────────────┼─────────┼───────────────────┤
146-
│ elastic-agent │ ${EXPECTED_AGENT_VERSION} │ running (healthy) │
147-
│ elasticsearch │ ${EXPECTED_VERSION} │ running (healthy) │
148-
│ fleet-server │ ${EXPECTED_AGENT_VERSION} │ running (healthy) │
149-
│ kibana │ ${EXPECTED_VERSION} │ running (healthy) │
150-
│ package-registry │ latest │ running (healthy) │
151-
╰──────────────────┴─────────┴───────────────────╯
148+
╭──────────────────┬─────────────────────┬───────────────────┬───────────────────┬────────────╮
149+
│ SERVICE │ VERSION │ STATUS │ IMAGE BUILD DATE │ VCS REF
150+
├──────────────────┼─────────────────────┼───────────────────┼───────────────────┼────────────┤
151+
│ elastic-agent │ ${EXPECTED_AGENT_VERSION} │ running (healthy) │ 2024-08-22T02:44Z │ b96a4ca8fa
152+
│ elasticsearch │ ${EXPECTED_VERSION} │ running (healthy) │ 2024-08-22T13:26Z │ 1362d56865
153+
│ fleet-server │ ${EXPECTED_AGENT_VERSION} │ running (healthy) │ 2024-08-22T02:44Z │ b96a4ca8fa
154+
│ kibana │ ${EXPECTED_VERSION} │ running (healthy) │ 2024-08-22T11:09Z │ cdcdfddd3f
155+
│ package-registry │ latest │ running (healthy) │ │
156+
╰──────────────────┴─────────────────────┴───────────────────┴───────────────────┴────────────╯
152157
EOF
153158

154159
NO_COLOR=true elastic-package stack status -v 2> "${OUTPUT_PATH_STATUS}/running.txt"
155160

156-
# Remove spaces to avoid issues with spaces between columns
161+
# Remove dates, commit IDs, and spaces to avoid issues.
157162
clean_status_output "${OUTPUT_PATH_STATUS}/expected_running.txt" > "${OUTPUT_PATH_STATUS}/expected_no_spaces.txt"
158163
clean_status_output "${OUTPUT_PATH_STATUS}/running.txt" > "${OUTPUT_PATH_STATUS}/running_no_spaces.txt"
159164

0 commit comments

Comments
 (0)