feat(dashboard): add health status to home page and dashboard (#3489)

* feat(dashboard): add health status to home page and dashboard

* fix(dashboard): code review updates, using builtin for substring search
pull/3549/head
Mike Church 2020-02-04 19:59:29 +01:00 committed by GitHub
parent cc8d3c8639
commit 6f59f130a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 17 deletions

View File

@ -3,6 +3,7 @@ package docker
import ( import (
"context" "context"
"log" "log"
"strings"
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
@ -126,6 +127,8 @@ func snapshotContainers(snapshot *portainer.Snapshot, cli *client.Client) error
runningContainers := 0 runningContainers := 0
stoppedContainers := 0 stoppedContainers := 0
healthyContainers := 0
unhealthyContainers := 0
stacks := make(map[string]struct{}) stacks := make(map[string]struct{})
for _, container := range containers { for _, container := range containers {
if container.State == "exited" { if container.State == "exited" {
@ -134,6 +137,12 @@ func snapshotContainers(snapshot *portainer.Snapshot, cli *client.Client) error
runningContainers++ runningContainers++
} }
if strings.Contains(container.Status, "(healthy)") {
healthyContainers++
} else if strings.Contains(container.Status, "(unhealthy)") {
unhealthyContainers++
}
for k, v := range container.Labels { for k, v := range container.Labels {
if k == "com.docker.compose.project" { if k == "com.docker.compose.project" {
stacks[v] = struct{}{} stacks[v] = struct{}{}
@ -143,6 +152,8 @@ func snapshotContainers(snapshot *portainer.Snapshot, cli *client.Client) error
snapshot.RunningContainerCount = runningContainers snapshot.RunningContainerCount = runningContainers
snapshot.StoppedContainerCount = stoppedContainers snapshot.StoppedContainerCount = stoppedContainers
snapshot.HealthyContainerCount = healthyContainers
snapshot.UnhealthyContainerCount = unhealthyContainers
snapshot.StackCount += len(stacks) snapshot.StackCount += len(stacks)
snapshot.SnapshotRaw.Containers = containers snapshot.SnapshotRaw.Containers = containers
return nil return nil

View File

@ -390,18 +390,20 @@ type (
// Snapshot represents a snapshot of a specific endpoint at a specific time // Snapshot represents a snapshot of a specific endpoint at a specific time
Snapshot struct { Snapshot struct {
Time int64 `json:"Time"` Time int64 `json:"Time"`
DockerVersion string `json:"DockerVersion"` DockerVersion string `json:"DockerVersion"`
Swarm bool `json:"Swarm"` Swarm bool `json:"Swarm"`
TotalCPU int `json:"TotalCPU"` TotalCPU int `json:"TotalCPU"`
TotalMemory int64 `json:"TotalMemory"` TotalMemory int64 `json:"TotalMemory"`
RunningContainerCount int `json:"RunningContainerCount"` RunningContainerCount int `json:"RunningContainerCount"`
StoppedContainerCount int `json:"StoppedContainerCount"` StoppedContainerCount int `json:"StoppedContainerCount"`
VolumeCount int `json:"VolumeCount"` HealthyContainerCount int `json:"HealthyContainerCount"`
ImageCount int `json:"ImageCount"` UnhealthyContainerCount int `json:"UnhealthyContainerCount"`
ServiceCount int `json:"ServiceCount"` VolumeCount int `json:"VolumeCount"`
StackCount int `json:"StackCount"` ImageCount int `json:"ImageCount"`
SnapshotRaw SnapshotRaw `json:"SnapshotRaw"` ServiceCount int `json:"ServiceCount"`
StackCount int `json:"StackCount"`
SnapshotRaw SnapshotRaw `json:"SnapshotRaw"`
} }
// SnapshotRaw represents all the information related to a snapshot as returned by the Docker API // SnapshotRaw represents all the information related to a snapshot as returned by the Docker API

View File

@ -248,6 +248,22 @@ angular.module('portainer.docker')
}).length; }).length;
}; };
}) })
.filter('healthycontainers', function () {
'use strict';
return function healthyContainersFilter(containers) {
return containers.filter(function (container) {
return container.Status === 'healthy';
}).length;
}
})
.filter('unhealthycontainers', function () {
'use strict';
return function unhealthyContainersFilter(containers) {
return containers.filter(function (container) {
return container.Status === 'unhealthy';
}).length;
}
})
.filter('imagestotalsize', function () { .filter('imagestotalsize', function () {
'use strict'; 'use strict';
return function (images) { return function (images) {

View File

@ -109,9 +109,13 @@
<div class="widget-icon blue pull-left"> <div class="widget-icon blue pull-left">
<i class="fa fa-server"></i> <i class="fa fa-server"></i>
</div> </div>
<div class="pull-right"> <div class="pull-right"style="padding-left: 5px;">
<div><i class="fa fa-heartbeat space-right green-icon"></i>{{ containers | runningcontainers }} running</div> <div><i class="fa fa-power-off space-right green-icon"></i>{{ containers | runningcontainers }} running</div>
<div><i class="fa fa-heartbeat space-right red-icon"></i>{{ containers | stoppedcontainers }} stopped</div> <div><i class="fa fa-power-off space-right red-icon"></i>{{ containers | stoppedcontainers }} stopped</div>
</div>
<div class="pull-right" style="padding-right: 5px;">
<div><i class="fa fa-heartbeat space-right green-icon"></i>{{ containers | healthycontainers }} healthy</div>
<div><i class="fa fa-heartbeat space-right orange-icon"></i>{{ containers | unhealthycontainers }} unhealthy</div>
</div> </div>
<div class="title">{{ containers.length }}</div> <div class="title">{{ containers.length }}</div>
<div class="comment">{{ containers.length === 1 ? 'Container' : 'Containers' }}</div> <div class="comment">{{ containers.length === 1 ? 'Container' : 'Containers' }}</div>

View File

@ -51,8 +51,11 @@
<i class="fa fa-server space-right" aria-hidden="true"></i>{{ $ctrl.model.Snapshots[0].RunningContainerCount + $ctrl.model.Snapshots[0].StoppedContainerCount }} {{ $ctrl.model.Snapshots[0].RunningContainerCount + $ctrl.model.Snapshots[0].StoppedContainerCount === 1 ? 'container' : 'containers' }} <i class="fa fa-server space-right" aria-hidden="true"></i>{{ $ctrl.model.Snapshots[0].RunningContainerCount + $ctrl.model.Snapshots[0].StoppedContainerCount }} {{ $ctrl.model.Snapshots[0].RunningContainerCount + $ctrl.model.Snapshots[0].StoppedContainerCount === 1 ? 'container' : 'containers' }}
<span ng-if="$ctrl.model.Snapshots[0].RunningContainerCount > 0 || $ctrl.model.Snapshots[0].StoppedContainerCount > 0"> <span ng-if="$ctrl.model.Snapshots[0].RunningContainerCount > 0 || $ctrl.model.Snapshots[0].StoppedContainerCount > 0">
- -
<i class="fa fa-heartbeat green-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].RunningContainerCount }} <i class="fa fa-power-off green-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].RunningContainerCount }}
<i class="fa fa-heartbeat red-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].StoppedContainerCount }} <i class="fa fa-power-off red-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].StoppedContainerCount }}
/
<i class="fa fa-heartbeat green-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].HealthyContainerCount }}
<i class="fa fa-heartbeat orange-icon" aria-hidden="true"></i> {{ $ctrl.model.Snapshots[0].UnhealthyContainerCount }}
</span> </span>
</span> </span>
<span style="padding: 0 7px 0 7px;"> <span style="padding: 0 7px 0 7px;">