Skip to content
This repository has been archived by the owner on Jan 8, 2024. It is now read-only.

Feature: CLI list deployments shows health for each entry #1594

Merged
merged 10 commits into from
Jun 10, 2021
3 changes: 3 additions & 0 deletions .changelog/1594.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
core/cli: List deployments shows status for each deployment
```
2 changes: 1 addition & 1 deletion builtin/docker/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func (p *Platform) Status(
result.HealthMessage = fmt.Sprintf("Container %q is reporting partially available!", containerInfo.Name)
}

result.TimeGenerated = ptypes.TimestampNow()
result.GeneratedTime = ptypes.TimestampNow()
log.Debug("status report complete")

// update output based on main health state
Expand Down
2 changes: 1 addition & 1 deletion builtin/k8s/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ func (p *Platform) Status(
step.Update("Building status report for running pods...")
result := buildStatusReport(podList)

result.TimeGenerated = ptypes.TimestampNow()
result.GeneratedTime = ptypes.TimestampNow()
log.Debug("status report complete")

// update output based on main health state
Expand Down
2 changes: 1 addition & 1 deletion builtin/k8s/releaser.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func (r *Releaser) Status(
step.Update("Building status report for running pods...")
result := buildStatusReport(podList)

result.TimeGenerated = ptypes.TimestampNow()
result.GeneratedTime = ptypes.TimestampNow()
log.Debug("status report complete")

// update output based on main health state
Expand Down
2 changes: 1 addition & 1 deletion builtin/nomad/platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ func (p *Platform) Status(

result.HealthMessage = *job.StatusDescription

result.TimeGenerated = ptypes.TimestampNow()
result.GeneratedTime = ptypes.TimestampNow()

s.Update("Finished building report for Nomad platform")
s.Done()
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ require (
github.com/hashicorp/vault/api v1.0.5-0.20200519221902-385fac77e20f
github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210526204726-417a273d6412
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210609145036-5c5b44751ee6
github.com/imdario/mergo v0.3.11
github.com/improbable-eng/grpc-web v0.13.0
github.com/kevinburke/go-bindata v3.22.0+incompatible
Expand Down
6 changes: 2 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -684,8 +684,8 @@ github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef h1:YKouRHFf
github.com/hashicorp/vault/sdk v0.1.14-0.20201202172114-ee5ebeb30fef/go.mod h1:cAGI4nVnEfAyMeqt9oB+Mase8DNn3qA/LDNHURiwssY=
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9 h1:i9hzlv2SpmaNcQ8ZLGn01fp2Gqyejj0juVs7rYDgecE=
github.com/hashicorp/waypoint-hzn v0.0.0-20201008221232-97cd4d9120b9/go.mod h1:ObgQSWSX9rsNofh16kctm6XxLW2QW1Ay6/9ris6T6DU=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210526204726-417a273d6412 h1:qw6H1ef5BJsze++0GoPrFNXw0lV57mk2ADvdau0l2Jw=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210526204726-417a273d6412/go.mod h1:3EzMFm8svUyyR35eop57AZmFBqFbIJVx6/MkALuNEjo=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210609145036-5c5b44751ee6 h1:zhcfxphKiDYtZHmtgl4YC4rhNxIzv0aJmcz2fejJT2g=
github.com/hashicorp/waypoint-plugin-sdk v0.0.0-20210609145036-5c5b44751ee6/go.mod h1:C6CXoZZFHsW8wb6WV6pIKZ5KFwd7XgK4GRD3hkt+lfg=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20190923154419-df201c70410d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
Expand Down Expand Up @@ -1566,7 +1566,6 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200715011427-11fb19a81f2c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201002142447-3860012362da/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5 h1:YejJbGvoWsTXHab4OKNrzk27Dr7s4lPLnewbHue1+gM=
google.golang.org/genproto v0.0.0-20201022181438-0ff5f38871d5/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
Expand All @@ -1588,7 +1587,6 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1 h1:DGeFlSan2f+WEtCERJ4J9GJWk15TxUi8QGagfI87Xyc=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
Expand Down
56 changes: 25 additions & 31 deletions internal/cli/deployment_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ import (
"github.com/posener/complete"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/anypb"

sdk "github.com/hashicorp/waypoint-plugin-sdk/proto/gen"
"github.com/hashicorp/waypoint-plugin-sdk/terminal"
clientpkg "github.com/hashicorp/waypoint/internal/client"
"github.com/hashicorp/waypoint/internal/clierrors"
Expand Down Expand Up @@ -112,24 +109,20 @@ func (c *DeploymentListCommand) Run(args []string) int {
sort.Sort(serversort.DeploymentCompleteDesc(resp.Deployments))

// get status reports
statusReportResp, err := client.GetLatestStatusReport(ctx, &pb.GetLatestStatusReportRequest{
statusReportsResp, err := client.ListStatusReports(ctx, &pb.ListStatusReportsRequest{
Application: app.Ref(),
Workspace: wsRef,
})

if status.Code(err) == codes.NotFound || status.Code(err) == codes.Unimplemented {
err = nil
statusReportResp = nil
statusReportsResp = nil
}
if err != nil {
izaaklauer marked this conversation as resolved.
Show resolved Hide resolved
app.UI.Output(clierrors.Humanize(err), terminal.WithErrorStyle())
return ErrSentinel
}

statusReport := &sdk.StatusReport{}
if statusReportResp != nil {
anypb.UnmarshalTo(statusReportResp.StatusReport, statusReport, proto.UnmarshalOptions{})
}

if c.flagJson {
return c.displayJson(resp.Deployments)
}
Expand All @@ -138,7 +131,7 @@ func (c *DeploymentListCommand) Run(args []string) int {

const bullet = "●"

for i, b := range resp.Deployments {
for _, b := range resp.Deployments {
// Determine our bullet
status := ""
statusColor := ""
Expand Down Expand Up @@ -177,28 +170,29 @@ func (c *DeploymentListCommand) Run(args []string) int {
completeTime = humanize.Time(t)
}

// Only display "Latest" report on Last deployment
var statusReportComplete string
if statusReportResp != nil {
if i == 0 { // Latest deployment
switch statusReport.Health {
case sdk.StatusReport_READY:
statusReportComplete = "✔"
case sdk.StatusReport_ALIVE:
statusReportComplete = "✔"
case sdk.StatusReport_DOWN:
statusReportComplete = "✖"
case sdk.StatusReport_PARTIAL:
statusReportComplete = "●"
case sdk.StatusReport_UNKNOWN:
statusReportComplete = "?"
}
if t, err := ptypes.Timestamp(statusReport.TimeGenerated); err == nil {
statusReportComplete = fmt.Sprintf("%s - %s", statusReportComplete, humanize.Time(t))
// Add status report information if we have any
statusReportComplete := "n/a"
for _, statusReport := range statusReportsResp.StatusReports {
if deploymentTargetId, ok := statusReport.TargetId.(*pb.StatusReport_DeploymentId); ok {
if deploymentTargetId.DeploymentId == b.Id {
switch statusReport.Health.HealthStatus {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to see we’re switching on the outer HealthStatus rather than the SDK’s Health enum.

case "READY":
statusReportComplete = "✔"
case "ALIVE":
statusReportComplete = "✔"
case "DOWN":
statusReportComplete = "✖"
case "PARTIAL":
statusReportComplete = "●"
case "UNKNOWN":
statusReportComplete = "?"
}

if t, err := ptypes.Timestamp(statusReport.GeneratedTime); err == nil {
statusReportComplete = fmt.Sprintf("%s - %s", statusReportComplete, humanize.Time(t))
}
}
}
} else {
statusReportComplete = "Unknown status"
}

var (
Expand Down
4 changes: 3 additions & 1 deletion internal/core/app_status_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,6 @@ func (op *statusReportOperation) Do(
// Add the deployment/release ID to the report.
// TODO: this is a stopgap solution - we should wire resource ID information into here in a more generic way
// rather than continue to append to this switch case.

switch target := op.Target.(type) {
case *pb.Deployment:
realMsg.TargetId = &pb.StatusReport_DeploymentId{DeploymentId: target.Id}
Expand All @@ -345,6 +344,9 @@ func (op *statusReportOperation) Do(
return nil, status.Errorf(codes.FailedPrecondition, "unsupported status operation type")
}

// Add the time generated to the outer status report
realMsg.GeneratedTime = report.GeneratedTime

op.result = result.(*sdk.StatusReport)

return result, nil
Expand Down
20 changes: 17 additions & 3 deletions internal/core/app_status_report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package core

import (
"context"
"google.golang.org/protobuf/types/known/timestamppb"
"testing"

"github.com/golang/protobuf/ptypes"
Expand Down Expand Up @@ -113,22 +114,28 @@ func TestAppDeploymentStatusReport(t *testing.T) {
require.NoError(err)
deploy := resp.Deployment

statusReportTs := timestamppb.Now()
mock.Status.On("StatusFunc").Return(func(context.Context) (*sdk.StatusReport, error) {
return &sdk.StatusReport{}, nil
return &sdk.StatusReport{
GeneratedTime: statusReportTs,
}, nil
})

// Status Report

srResp, err := app.DeploymentStatusReport(context.Background(), deploy)
statusReport := &sdk.StatusReport{}
anypb.UnmarshalTo(srResp.StatusReport, statusReport, proto.UnmarshalOptions{})
require.NoError(err)
require.NotNil(srResp.StatusReport)
require.NotNil(statusReport.Health)

// Verify that we have a Target of the right type with the right id
require.IsType(srResp.TargetId, &pb.StatusReport_DeploymentId{})
require.Equal(srResp.TargetId.(*pb.StatusReport_DeploymentId).DeploymentId, deploy.Id)

// Verify that the status report timestamp made it into the server resp
require.NotNil(srResp.GeneratedTime)
require.True(srResp.GeneratedTime.AsTime().Equal(statusReportTs.AsTime()))
})
}

Expand Down Expand Up @@ -244,8 +251,11 @@ func TestAppReleaseStatusReport(t *testing.T) {
require.NoError(err)
release := releaseResp.Release

statusReportTs := timestamppb.Now()
mock.Status.On("StatusFunc").Return(func(context.Context) (*sdk.StatusReport, error) {
return &sdk.StatusReport{}, nil
return &sdk.StatusReport{
GeneratedTime: statusReportTs,
}, nil
})

// Status Report
Expand All @@ -256,9 +266,13 @@ func TestAppReleaseStatusReport(t *testing.T) {
require.NotNil(srResp.StatusReport)
require.NotNil(statusReport.Health)

// Verify that we have a Target of the right type with the right id
require.IsType(srResp.TargetId, &pb.StatusReport_ReleaseId{})
require.Equal(srResp.TargetId.(*pb.StatusReport_ReleaseId).ReleaseId, release.Id)

// Verify that the status report timestamp made it into the server resp
require.NotNil(srResp.GeneratedTime)
require.True(srResp.GeneratedTime.AsTime().Equal(statusReportTs.AsTime()))
})
}

Expand Down
Loading