diff --git a/zun_ui/static/dashboard/container/container.scss b/zun_ui/static/dashboard/container/container.scss index 92a703f..74ec620 100644 --- a/zun_ui/static/dashboard/container/container.scss +++ b/zun_ui/static/dashboard/container/container.scss @@ -1,4 +1,5 @@ @import "containers/containers"; +@import "hosts/hosts"; .batch-action { float: right; diff --git a/zun_ui/static/dashboard/container/hosts/details/details.module.js b/zun_ui/static/dashboard/container/hosts/details/details.module.js new file mode 100644 index 0000000..b4e4638 --- /dev/null +++ b/zun_ui/static/dashboard/container/hosts/details/details.module.js @@ -0,0 +1,51 @@ +/** + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +(function() { + 'use strict'; + + /** + * @ngdoc overview + * @ngname horizon.dashboard.container.hosts.details + * + * @description + * Provides details for host. + */ + angular.module('horizon.dashboard.container.hosts.details', + ['horizon.framework.conf', 'horizon.app.core']) + .run(registerDetails); + + registerDetails.$inject = [ + 'horizon.dashboard.container.hosts.basePath', + 'horizon.dashboard.container.hosts.resourceType', + 'horizon.dashboard.container.hosts.service', + 'horizon.framework.conf.resource-type-registry.service' + ]; + + function registerDetails( + basePath, + resourceType, + hostService, + registry + ) { + registry.getResourceType(resourceType) + .setLoadFunction(hostService.getHostPromise) + .detailsViews + .append({ + id: 'hostDetailsOverview', + name: gettext('Overview'), + template: basePath + 'details/overview.html' + }); + } +})(); diff --git a/zun_ui/static/dashboard/container/hosts/details/overview.controller.js b/zun_ui/static/dashboard/container/hosts/details/overview.controller.js new file mode 100644 index 0000000..0b4de45 --- /dev/null +++ b/zun_ui/static/dashboard/container/hosts/details/overview.controller.js @@ -0,0 +1,102 @@ +/* + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +(function() { + "use strict"; + + angular + .module('horizon.dashboard.container.hosts') + .controller('horizon.dashboard.container.hosts.OverviewController', controller); + + controller.$inject = [ + '$scope' + ]; + + function controller( + $scope + ) { + var ctrl = this; + ctrl.chartSettings = { + innerRadius: 24, + outerRadius: 48, + titleClass: "pie-chart-title-medium", + showTitle: false, + showLabel: true, + showLegend: false, + tooltipIcon: 'fa-square' + }; + // Chart data is watched by pie-chart directive. + // So to refresh chart after retrieving data, update whole of 'data' array. + ctrl.chartDataMem = { + maxLimit: 10, + data: [] + }; + ctrl.chartDataCpu = { + maxLimit: 10, + data: [] + }; + ctrl.chartDataDisk = { + maxLimit: 10, + data: [] + }; + // container for temporal chart data + var dataMem = []; + var dataCpu = []; + var dataDisk = []; + + $scope.context.loadPromise.then(onGetHost); + + function onGetHost(host) { + ctrl.host = host.data; + + // set data for memory chart + dataMem = [ + {label: gettext("Used"), value: host.data.mem_used, colorClass: "exists"}, + {label: gettext("Margin"), value: host.data.mem_total - host.data.mem_used, + colorClass: "margin"} + ]; + ctrl.chartDataMem = generateChartData(dataMem, gettext("Memory")); + + // set data for CPU chart + dataCpu = [ + {label: gettext("Used"), value: host.data.cpu_used, colorClass: "exists"}, + {label: gettext("Margin"), value: host.data.cpus - host.data.cpu_used, + colorClass: "margin"} + ]; + ctrl.chartDataCpu = generateChartData(dataCpu, gettext("CPU")); + + // set data for disk chart + dataDisk = [ + {label: gettext("Used"), value: host.data.disk_used, colorClass: "exists"}, + {label: gettext("Margin"), value: host.data.disk_total - host.data.disk_used, + colorClass: "margin"} + ]; + ctrl.chartDataDisk = generateChartData(dataDisk, gettext("Disk")); + } + + function generateChartData(data, title) { + var sum = data[0].value; + var max = data[0].value + data[1].value; + var percent = Math.round(sum / max * 100); + var overMax = percent > 100; + var result = { + title: title, + label: percent + '%', + maxLimit: max, + overMax: overMax, + data: data + }; + return result; + } + } +})(); diff --git a/zun_ui/static/dashboard/container/hosts/details/overview.html b/zun_ui/static/dashboard/container/hosts/details/overview.html new file mode 100644 index 0000000..eeca846 --- /dev/null +++ b/zun_ui/static/dashboard/container/hosts/details/overview.html @@ -0,0 +1,60 @@ +
+
+
+

Usage

+
+
+
+

Memory

+
+ +
+
Used {$ ctrl.host.mem_used | mb $} of {$ ctrl.host.mem_total | mb $}
+
+
+
+

CPU

+
+ +
+
Used {$ ctrl.host.cpu_used $} of {$ ctrl.host.cpus $}
+
+
+
+

Disk

+
+ +
+
Used {$ ctrl.host.disk_used | gb $} of {$ ctrl.host.disk_total | gb $}
+
+
+
+
+
+
+
+

Info

+
+ + +
+
+

Miscellaneous

+
+ + +
+
+
\ No newline at end of file diff --git a/zun_ui/static/dashboard/container/hosts/hosts.module.js b/zun_ui/static/dashboard/container/hosts/hosts.module.js index 1ba6ab9..e40569b 100644 --- a/zun_ui/static/dashboard/container/hosts/hosts.module.js +++ b/zun_ui/static/dashboard/container/hosts/hosts.module.js @@ -25,7 +25,8 @@ */ angular .module('horizon.dashboard.container.hosts', [ - 'ngRoute' + 'ngRoute', + 'horizon.dashboard.container.hosts.details' ]) .constant('horizon.dashboard.container.hosts.resourceType', 'OS::Zun::Host') .run(run) @@ -45,6 +46,7 @@ // for detail summary view on table row. .setSummaryTemplateUrl(basePath + 'drawer.html') // for table row items and detail summary view. + .setDefaultIndexUrl('/admin/container/hosts/') .setProperties(hostProperties()) .setListFunction(hostService.getHostsPromise) .tableColumns @@ -55,7 +57,8 @@ .append({ id: 'hostname', priority: 1, - sortDefault: true + sortDefault: true, + urlFunction: hostService.getDetailsPath }) .append({ id: 'mem_total', @@ -95,13 +98,14 @@ 'disk_used': { label: gettext('Disk Used'), filters: ['noValue', 'gb'] }, 'disk_quota_supported': { label: gettext('Disk Quota Supported'), filters: ['noValue', 'yesno'] }, - 'total_containers': { label: gettext('Disk Used'), filters: ['noValue'] }, + 'total_containers': { label: gettext('Total Containers'), filters: ['noValue'] }, 'os': { label: gettext('OS'), filters: ['noValue'] }, 'os_type': { label: gettext('OS Type'), filters: ['noValue'] }, 'architecture': { label: gettext('Architecture'), filters: ['noValue'] }, 'kernel_version': { label: gettext('Kernel Version'), filters: ['noValue'] }, - 'runtimes': { label: gettext('Runtimes'), filters: ['noValue'] }, - 'labels': { label: gettext('Labels'), filters: ['noValue'] } + 'runtimes': { label: gettext('Runtimes'), filters: ['noValue', 'json'] }, + 'labels': { label: gettext('Labels'), filters: ['noValue', 'json'] }, + 'links': { label: gettext('Links'), filters: ['noValue', 'json'] } }; } diff --git a/zun_ui/static/dashboard/container/hosts/hosts.scss b/zun_ui/static/dashboard/container/hosts/hosts.scss new file mode 100644 index 0000000..009af36 --- /dev/null +++ b/zun_ui/static/dashboard/container/hosts/hosts.scss @@ -0,0 +1,45 @@ +.pie-chart { + display: block; + .svg-pie-chart { + .slice { + &.exists { + fill: lighten(blue, 20%); + } + &.margin { + fill: $gray-lighter; + } + } + } + .pie-chart-legend { + display: inline-block; + margin-left: 20px; + .slice-legend { + .slice-key { + &.exists { + background-color: lighten(blue, 20%); + } + &.margin { + background-color: $gray-lighter; + } + } + .chartless { + &.exists { + color: lighten(blue, 20%); + } + &.margin { + color: $gray-lighter; + } + } + } + } +} +.chart-tooltip { + span.fa { + &.exists { + color: lighten(blue, 20%); + } + &.margin { + color: $gray-lighter; + } + } +} \ No newline at end of file diff --git a/zun_ui/static/dashboard/container/hosts/hosts.service.js b/zun_ui/static/dashboard/container/hosts/hosts.service.js index 964335e..69bd465 100644 --- a/zun_ui/static/dashboard/container/hosts/hosts.service.js +++ b/zun_ui/static/dashboard/container/hosts/hosts.service.js @@ -33,9 +33,36 @@ */ function hostsService(detailRoute, zun) { return { - getHostsPromise: getHostsPromise + getDetailsPath: getDetailsPath, + getHostsPromise: getHostsPromise, + getHostPromise: getHostPromise }; + /* + * @ngdoc function + * @name getDetailsPath + * @param item {Object} - The host object + * @description + * Returns the relative path to the details view. + */ + function getDetailsPath(item) { + return detailRoute + 'OS::Zun::Host/' + item.id; + } + + /* + * @ngdoc function + * @name getHostPromise + * @description + * Given an id, returns a promise for the host data. + */ + function getHostPromise(identifier) { + return zun.getHost(identifier).then(modifyDetails); + } + + function modifyDetails(response) { + return {data: modifyItem(response.data)}; + } + /* * @ngdoc function * @name getHostsPromise @@ -49,12 +76,12 @@ function modifyResponse(response) { return {data: {items: response.data.items.map(modifyItem)}}; + } - function modifyItem(item) { - var timestamp = new Date(); - item.trackBy = item.id.concat(timestamp.getTime()); - return item; - } + function modifyItem(item) { + var timestamp = new Date(); + item.trackBy = item.id.concat(timestamp.getTime()); + return item; } } })();