Add docker status and images info to /docker page.
This commit is contained in:
parent
8164fac617
commit
f54e10b7e8
@ -64,6 +64,36 @@ const containersHtmlTemplate = `
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
{{if .DockerStatus}}
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<h3>Driver Status</h3>
|
||||||
|
</div>
|
||||||
|
<ul class="list-group">
|
||||||
|
{{range $dockerstatus := .DockerStatus}}
|
||||||
|
<li class ="list-group-item"><span class="stat-label">{{$dockerstatus.Key}}</span> {{$dockerstatus.Value}}</li>
|
||||||
|
{{end}}
|
||||||
|
{{if .DockerDriverStatus}}
|
||||||
|
<li class ="list-group-item"><span class="stat-label">Storage<br></span>
|
||||||
|
<ul class="list-group">
|
||||||
|
{{range $driverstatus := .DockerDriverStatus}}
|
||||||
|
<li class="list-group-item"><span class="stat-label">{{$driverstatus.Key}}</span> {{$driverstatus.Value}}</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
{{if .DockerImages}}
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="page-header">
|
||||||
|
<h3>Images</h3>
|
||||||
|
</div>
|
||||||
|
<div id="docker-images"></div>
|
||||||
|
<br><br>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
{{if .ResourcesAvailable}}
|
{{if .ResourcesAvailable}}
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
@ -186,6 +216,7 @@ const containersHtmlTemplate = `
|
|||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
startPage({{.ContainerName}}, {{.CpuAvailable}}, {{.MemoryAvailable}}, {{.Root}});
|
startPage({{.ContainerName}}, {{.CpuAvailable}}, {{.MemoryAvailable}}, {{.Root}});
|
||||||
|
drawImages({{.DockerImages}});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
@ -29,6 +30,25 @@ import (
|
|||||||
|
|
||||||
const DockerPage = "/docker/"
|
const DockerPage = "/docker/"
|
||||||
|
|
||||||
|
func toStatusKV(status manager.DockerStatus) ([]keyVal, []keyVal) {
|
||||||
|
ds := []keyVal{
|
||||||
|
{Key: "Driver", Value: status.Driver},
|
||||||
|
}
|
||||||
|
for k, v := range status.DriverStatus {
|
||||||
|
ds = append(ds, keyVal{Key: k, Value: v})
|
||||||
|
}
|
||||||
|
return []keyVal{
|
||||||
|
{Key: "Docker Version", Value: status.Version},
|
||||||
|
{Key: "Kernel Version", Value: status.KernelVersion},
|
||||||
|
{Key: "OS Version", Value: status.OS},
|
||||||
|
{Key: "Host Name", Value: status.Hostname},
|
||||||
|
{Key: "Docker Root Directory", Value: status.RootDir},
|
||||||
|
{Key: "Execution Driver", Value: status.ExecDriver},
|
||||||
|
{Key: "Number of Images", Value: strconv.Itoa(status.NumImages)},
|
||||||
|
{Key: "Number of Containers", Value: strconv.Itoa(status.NumContainers)},
|
||||||
|
}, ds
|
||||||
|
}
|
||||||
|
|
||||||
func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {
|
func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
@ -54,6 +74,19 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get Docker status
|
||||||
|
status, err := m.DockerInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dockerStatus, driverStatus := toStatusKV(status)
|
||||||
|
// Get Docker Images
|
||||||
|
images, err := m.DockerImages()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
dockerContainersText := "Docker Containers"
|
dockerContainersText := "Docker Containers"
|
||||||
data = &pageData{
|
data = &pageData{
|
||||||
DisplayName: dockerContainersText,
|
DisplayName: dockerContainersText,
|
||||||
@ -62,8 +95,11 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
Text: dockerContainersText,
|
Text: dockerContainersText,
|
||||||
Link: DockerPage,
|
Link: DockerPage,
|
||||||
}},
|
}},
|
||||||
Subcontainers: subcontainers,
|
Subcontainers: subcontainers,
|
||||||
Root: rootDir,
|
Root: rootDir,
|
||||||
|
DockerStatus: dockerStatus,
|
||||||
|
DockerDriverStatus: driverStatus,
|
||||||
|
DockerImages: images,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Get the container.
|
// Get the container.
|
||||||
@ -92,7 +128,6 @@ func serveDockerPage(m manager.Manager, w http.ResponseWriter, u *url.URL) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
data = &pageData{
|
data = &pageData{
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
ContainerName: cont.Name,
|
ContainerName: cont.Name,
|
||||||
|
@ -37,6 +37,11 @@ type link struct {
|
|||||||
Link string
|
Link string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type keyVal struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
type pageData struct {
|
type pageData struct {
|
||||||
DisplayName string
|
DisplayName string
|
||||||
ContainerName string
|
ContainerName string
|
||||||
@ -52,6 +57,9 @@ type pageData struct {
|
|||||||
NetworkAvailable bool
|
NetworkAvailable bool
|
||||||
FsAvailable bool
|
FsAvailable bool
|
||||||
Root string
|
Root string
|
||||||
|
DockerStatus []keyVal
|
||||||
|
DockerDriverStatus []keyVal
|
||||||
|
DockerImages []manager.DockerImage
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -39,6 +39,17 @@ const containersCss = `
|
|||||||
.isolation-title {
|
.isolation-title {
|
||||||
color:#FFFFFF;
|
color:#FFFFFF;
|
||||||
}
|
}
|
||||||
|
.table-row {
|
||||||
|
font-family: "courier", "monospace";
|
||||||
|
font-size: 15px;
|
||||||
|
text-align: right;
|
||||||
|
vertical-align: top;
|
||||||
|
border: 5px;
|
||||||
|
margin-left: 3px;
|
||||||
|
margin-right: 3px;
|
||||||
|
margin-top: 3px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
#logo {
|
#logo {
|
||||||
height: 200px;
|
height: 200px;
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
|
@ -35,7 +35,7 @@ function humanizeMetric(num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw a table.
|
// Draw a table.
|
||||||
function drawTable(seriesTitles, titleTypes, data, elementId) {
|
function drawTable(seriesTitles, titleTypes, data, elementId, numPages) {
|
||||||
var dataTable = new google.visualization.DataTable();
|
var dataTable = new google.visualization.DataTable();
|
||||||
for (var i = 0; i < seriesTitles.length; i++) {
|
for (var i = 0; i < seriesTitles.length; i++) {
|
||||||
dataTable.addColumn(titleTypes[i], seriesTitles[i]);
|
dataTable.addColumn(titleTypes[i], seriesTitles[i]);
|
||||||
@ -45,10 +45,17 @@ function drawTable(seriesTitles, titleTypes, data, elementId) {
|
|||||||
window.charts[elementId] = new google.visualization.Table(document.getElementById(elementId));
|
window.charts[elementId] = new google.visualization.Table(document.getElementById(elementId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cssClassNames = {
|
||||||
|
'headerRow': '',
|
||||||
|
'tableRow': 'table-row',
|
||||||
|
'oddTableRow': 'table-row'
|
||||||
|
};
|
||||||
var opts = {
|
var opts = {
|
||||||
alternatingRowStyle: true,
|
alternatingRowStyle: true,
|
||||||
page: 'enable',
|
page: 'enable',
|
||||||
pageSize: 25,
|
pageSize: numPages,
|
||||||
|
allowHtml: true,
|
||||||
|
cssClassNames: cssClassNames,
|
||||||
};
|
};
|
||||||
window.charts[elementId].draw(dataTable, opts);
|
window.charts[elementId].draw(dataTable, opts);
|
||||||
}
|
}
|
||||||
@ -425,11 +432,44 @@ function drawFileSystemUsage(machineInfo, stats) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function drawImages(images) {
|
||||||
|
if (images == null || images.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.charts = {};
|
||||||
|
var titles = ["Repository", "Tags", "ID", "Virtual Size", "Creation Time"];
|
||||||
|
var titleTypes = ['string', 'string', 'string', 'number', 'number'];
|
||||||
|
var data = [];
|
||||||
|
for (var i = 0; i < images.length; i++) {
|
||||||
|
var elements = [];
|
||||||
|
var tags = [];
|
||||||
|
var repos = images[i].repo_tags[0].split(":");
|
||||||
|
repos.splice(-1,1)
|
||||||
|
for (var j = 0; j < images[i].repo_tags.length; j++) {
|
||||||
|
var splits = images[i].repo_tags[j].split(":")
|
||||||
|
if (splits.length > 1) {
|
||||||
|
tags.push(splits[splits.length - 1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elements.push(repos.join(":"));
|
||||||
|
elements.push(tags.join(", "));
|
||||||
|
elements.push(images[i].id.substr(0,24));
|
||||||
|
elements.push({v: images[i].virtual_size, f: humanizeIEC(images[i].virtual_size)});
|
||||||
|
var d = new Date(images[i].created * 1000);
|
||||||
|
elements.push({v: images[i].created, f: d.toLocaleString()});
|
||||||
|
data.push(elements);
|
||||||
|
}
|
||||||
|
drawTable(titles, titleTypes, data, "docker-images", 30);
|
||||||
|
}
|
||||||
|
|
||||||
function drawProcesses(processInfo) {
|
function drawProcesses(processInfo) {
|
||||||
|
if (processInfo.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
var titles = ["User", "PID", "PPID", "Start Time", "CPU %", "MEM %", "RSS", "Virtual Size", "Status", "Running Time", "Command"];
|
var titles = ["User", "PID", "PPID", "Start Time", "CPU %", "MEM %", "RSS", "Virtual Size", "Status", "Running Time", "Command"];
|
||||||
var titleTypes = ['string', 'number', 'number', 'string', 'number', 'number', 'number', 'number', 'string', 'string', 'string'];
|
var titleTypes = ['string', 'number', 'number', 'string', 'number', 'number', 'number', 'number', 'string', 'string', 'string'];
|
||||||
var data = []
|
var data = []
|
||||||
for (var i = 1; i < processInfo.length; i++) {
|
for (var i = 0; i < processInfo.length; i++) {
|
||||||
var elements = [];
|
var elements = [];
|
||||||
elements.push(processInfo[i].user);
|
elements.push(processInfo[i].user);
|
||||||
elements.push(processInfo[i].pid);
|
elements.push(processInfo[i].pid);
|
||||||
@ -444,7 +484,7 @@ function drawProcesses(processInfo) {
|
|||||||
elements.push(processInfo[i].cmd);
|
elements.push(processInfo[i].cmd);
|
||||||
data.push(elements);
|
data.push(elements);
|
||||||
}
|
}
|
||||||
drawTable(titles, titleTypes, data, "processes-top");
|
drawTable(titles, titleTypes, data, "processes-top", 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the filesystem usage nodes.
|
// Draw the filesystem usage nodes.
|
||||||
|
Loading…
Reference in New Issue
Block a user