YUNIKORN-250: Display queue properties in queues page (#41)
diff --git a/Makefile b/Makefile
index 8b4fe9c..beaf7d4 100644
--- a/Makefile
+++ b/Makefile
@@ -39,7 +39,7 @@
.PHONY: check-license
check-license:
- @echo "checking license header"
+ @echo "Checking license header"
@licRes=$$(grep -Lr --exclude-dir={node_modules,dist} --include=*.{sh,md,yaml,yml,js,ts,html,js,scss} "Licensed to the Apache Software Foundation" .) ; \
if [ -n "$${licRes}" ]; then \
echo "following files have incorrect license header:\n$${licRes}" ; \
@@ -69,7 +69,7 @@
# Build an image based on the production ready version
.PHONY: image
image:
- @echo "building web UI docker image"
+ @echo "Building web UI docker image"
@SHA=$$(git rev-parse --short=12 HEAD) ; \
docker build -t ${REGISTRY}/yunikorn:web-${VERSION} . \
--label "GitRevision=$${SHA}" \
@@ -96,6 +96,6 @@
.PHONY: push_image
push_image: image
- @echo "push docker images"
+ @echo "Pushing web UI docker image"
echo "${DOCKER_PASSWORD}" | docker login -u "${DOCKER_USERNAME}" --password-stdin
docker push ${REGISTRY}/yunikorn:web-${VERSION}
diff --git a/jsdb.json b/jsdb.json
index a2c3c9e..c512679 100644
--- a/jsdb.json
+++ b/jsdb.json
@@ -1,7 +1,22 @@
{
"clusters": [
{
- "clusterName": "kubernetes",
+ "clusterName": "cluster-1",
+ "totalApplications": "1",
+ "failedApplications": "",
+ "pendingApplications": "",
+ "runningApplications": "1",
+ "completedApplications": "",
+ "totalContainers": "2",
+ "failedContainers": "",
+ "pendingContainers": "",
+ "runningContainers": "2",
+ "activeNodes": "1",
+ "totalNodes": "1",
+ "failedNodes": ""
+ },
+ {
+ "clusterName": "cluster-2",
"totalApplications": "1",
"failedApplications": "",
"pendingApplications": "",
@@ -17,56 +32,65 @@
}
],
"queues": {
- "partitionname": "[my-kube-cluster]default",
+ "partitionName": "[mycluster]default",
"capacity": {
- "capacity": "map[vcore:96000 memory:810085]",
+ "capacity": "map[ephemeral-storage:56453061334 hugepages-1Gi:0 hugepages-2Mi:0 memory:5869 pods:110 vcore:4000]",
"usedcapacity": "0"
},
"nodes": null,
"queues": {
"queuename": "root",
- "status": "RUNNING",
+ "status": "Active",
"capacities": {
"capacity": "[memory:1000000 vcore:100000]",
- "maxcapacity": "[memory:1000000 vcore:100000]",
- "usedcapacity": "[memory:5908 vcore:4000]",
- "absusedcapacity": "20"
+ "maxcapacity": "[ephemeral-storage:56453061334 hugepages-1Gi:0 hugepages-2Mi:0 memory:5869 pods:110 vcore:4000]",
+ "usedcapacity": "[memory:1024 vcore:500]",
+ "absusedcapacity": "[memory:17 vcore:12]"
},
"queues": [
{
"queuename": "advertisement",
- "status": "RUNNING",
+ "status": "Active",
"capacities": {
"capacity": "[memory:500000 vcore:50000]",
- "maxcapacity": "[memory:500000 vcore:50000]",
- "usedcapacity": "[memory:5908 vcore:4000]",
- "absusedcapacity": "20"
+ "maxcapacity": "[memory:800000 vcore:80000]",
+ "usedcapacity": "[]",
+ "absusedcapacity": "[]"
},
- "queues": null
+ "queues": null,
+ "properties": {
+ "property2": "value2",
+ "someProperty": "someValue"
+ }
},
{
"queuename": "search",
- "status": "RUNNING",
+ "status": "Active",
"capacities": {
"capacity": "[memory:400000 vcore:40000]",
- "maxcapacity": "[memory:400000 vcore:40000]",
+ "maxcapacity": "[memory:600000 vcore:60000]",
"usedcapacity": "[]",
- "absusedcapacity": "20"
+ "absusedcapacity": "[]"
},
- "queues": null
+ "queues": null,
+ "properties": {}
},
{
"queuename": "sandbox",
- "status": "RUNNING",
+ "status": "Active",
"capacities": {
"capacity": "[memory:100000 vcore:10000]",
- "maxcapacity": "[vcore:10000 memory:100000]",
- "usedcapacity": "[]",
- "absusedcapacity": "20"
+ "maxcapacity": "[memory:100000 vcore:10000]",
+ "usedcapacity": "[memory:1024 vcore:500]",
+ "absusedcapacity": "[memory:1 vcore:5]"
},
- "queues": null
+ "queues": null,
+ "properties": {}
}
- ]
+ ],
+ "properties": {
+ "property1": "value1"
+ }
}
},
"apps": [
@@ -171,15 +195,15 @@
},
{
"timestamp": 1585238443804046000,
- "totalApplications": "1"
+ "totalApplications": "2"
},
{
"timestamp": 1585238503806253000,
- "totalApplications": "2"
+ "totalApplications": "1"
},
{
"timestamp": 1585238563807452000,
- "totalApplications": "2"
+ "totalApplications": "3"
}
],
"containerHistory": [
@@ -197,15 +221,15 @@
},
{
"timestamp": 1585238443804046000,
- "totalContainers": "1"
+ "totalContainers": "2"
},
{
"timestamp": 1585238503806253000,
- "totalContainers": "2"
+ "totalContainers": "1"
},
{
"timestamp": 1585238563807452000,
- "totalContainers": "2"
+ "totalContainers": "3"
}
],
"nodes": [
diff --git a/src/app/components/queues-view/queues-view.component.html b/src/app/components/queues-view/queues-view.component.html
index bcd5838..72e2f85 100644
--- a/src/app/components/queues-view/queues-view.component.html
+++ b/src/app/components/queues-view/queues-view.component.html
@@ -75,6 +75,10 @@
<div class="left-item">Absolute Used Capacity:</div>
<div class="right-item">{{ selectedQueue.absoluteUsedCapacity }}</div>
</div>
+ <div class="flex-grid item-wrapper" *ngFor="let prop of selectedQueue.queueProperties">
+ <div class="left-item">{{ prop.name }}:</div>
+ <div class="right-item">{{ prop.value }}</div>
+ </div>
</div>
</mat-drawer-content>
</mat-drawer>
diff --git a/src/app/models/queue-info.model.ts b/src/app/models/queue-info.model.ts
index 04615f9..d7b1c76 100644
--- a/src/app/models/queue-info.model.ts
+++ b/src/app/models/queue-info.model.ts
@@ -31,6 +31,12 @@
isLeafQueue: boolean;
isExpanded = false;
isSelected = false;
+ queueProperties: QueuePropertyItem[];
+}
+
+export interface QueuePropertyItem {
+ name: string;
+ value: string;
}
export interface SchedulerInfo {
diff --git a/src/app/services/scheduler/scheduler.service.ts b/src/app/services/scheduler/scheduler.service.ts
index 186026f..84d846d 100644
--- a/src/app/services/scheduler/scheduler.service.ts
+++ b/src/app/services/scheduler/scheduler.service.ts
@@ -21,7 +21,7 @@
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
-import { QueueInfo } from '@app/models/queue-info.model';
+import { QueueInfo, QueuePropertyItem } from '@app/models/queue-info.model';
import { EnvconfigService } from '../envconfig/envconfig.service';
import { ClusterInfo } from '@app/models/cluster-info.model';
import { CommonUtil } from '@app/utils/common.util';
@@ -45,9 +45,7 @@
public fetchClusterByName(clusterName: string): Observable<ClusterInfo> {
return this.fetchClusterList().pipe(
- map(data => {
- return data.find(obj => obj.clusterName === clusterName);
- })
+ map(data => data.find(obj => obj.clusterName === clusterName))
);
}
@@ -63,6 +61,7 @@
rootQueue.children = null;
rootQueue.isLeafQueue = false;
this.fillQueueCapacities(rootQueueData, rootQueue);
+ this.fillQueueProperties(rootQueueData, rootQueue);
rootQueue = this.generateQueuesTree(rootQueueData, rootQueue);
}
const partitionName = data['partitionname'] || '';
@@ -216,14 +215,15 @@
private generateQueuesTree(data: any, currentQueue: QueueInfo) {
if (data && data.queues && data.queues.length > 0) {
const chilrenQs = [];
- data.queues.forEach(queue => {
+ data.queues.forEach(queueData => {
const childQueue = new QueueInfo();
- childQueue.queueName = '' + queue.queuename;
- childQueue.state = queue.status || 'RUNNING';
+ childQueue.queueName = '' + queueData.queuename;
+ childQueue.state = queueData.status || 'RUNNING';
childQueue.parentQueue = currentQueue ? currentQueue : null;
- this.fillQueueCapacities(queue, childQueue);
+ this.fillQueueCapacities(queueData, childQueue);
+ this.fillQueueProperties(queueData, childQueue);
chilrenQs.push(childQueue);
- return this.generateQueuesTree(queue, childQueue);
+ return this.generateQueuesTree(queueData, childQueue);
});
currentQueue.children = chilrenQs;
currentQueue.isLeafQueue = false;
@@ -239,15 +239,27 @@
const maxCap = data['capacities']['maxcapacity'] as string;
const absUsedCapacity = data['capacities']['absusedcapacity'] as string;
- const configCapResources = this.splitCapacity(configCap, NOT_AVAILABLE);
- const usedCapResources = this.splitCapacity(usedCap, NOT_AVAILABLE);
- const maxCapResources = this.splitCapacity(maxCap, NOT_AVAILABLE);
- const absUsedCapacityResources = this.splitCapacity(absUsedCapacity, NOT_AVAILABLE);
+ queue.capacity = this.formatCapacity(this.splitCapacity(configCap, NOT_AVAILABLE));
+ queue.maxCapacity = this.formatCapacity(this.splitCapacity(maxCap, NOT_AVAILABLE));
+ queue.usedCapacity = this.formatCapacity(this.splitCapacity(usedCap, NOT_AVAILABLE));
+ queue.absoluteUsedCapacity = this.formatAbsCapacity(
+ this.splitCapacity(absUsedCapacity, NOT_AVAILABLE)
+ );
+ }
- queue.capacity = this.formatCapacity(configCapResources);
- queue.maxCapacity = this.formatCapacity(maxCapResources);
- queue.usedCapacity = this.formatCapacity(usedCapResources);
- queue.absoluteUsedCapacity = this.formatAbsCapacity(absUsedCapacityResources);
+ private fillQueueProperties(data: any, queue: QueueInfo) {
+ if (data.properties && !CommonUtil.isEmpty(data.properties)) {
+ const dataProps = Object.entries<string>(data.properties);
+
+ queue.queueProperties = dataProps.map(prop => {
+ return {
+ name: prop[0],
+ value: prop[1]
+ } as QueuePropertyItem;
+ });
+ } else {
+ queue.queueProperties = [];
+ }
}
private splitCapacity(capacity: string = '', defaultValue: string): ResourceInfo {
@@ -279,11 +291,15 @@
private formatCapacity(resourceInfo: ResourceInfo) {
const formatted = [];
if (resourceInfo.memory !== NOT_AVAILABLE) {
- formatted.push(`[memory: ${CommonUtil.formatMemory(+resourceInfo.memory)}`);
+ formatted.push(`[memory: ${CommonUtil.formatMemory(resourceInfo.memory)}`);
} else {
formatted.push(`[memory: ${resourceInfo.memory}`);
}
- formatted.push(`vcore: ${resourceInfo.vcore}]`);
+ if (resourceInfo.vcore !== NOT_AVAILABLE) {
+ formatted.push(`vcore: ${CommonUtil.formatCount(resourceInfo.vcore)}]`);
+ } else {
+ formatted.push(`vcore: ${resourceInfo.vcore}]`);
+ }
return formatted.join(', ');
}
diff --git a/src/app/utils/common.util.ts b/src/app/utils/common.util.ts
index 299c41d..c2d11c6 100644
--- a/src/app/utils/common.util.ts
+++ b/src/app/utils/common.util.ts
@@ -17,39 +17,52 @@
*/
export class CommonUtil {
- static createUniqId(prefix?: string) {
+ static createUniqId(prefix?: string): string {
const uniqid = Math.random()
.toString(36)
.substr(2);
+
if (prefix) {
return prefix + uniqid;
}
+
return uniqid;
}
- static formatMemory(value: number) {
- let toUnit = 'MB';
- let toValue = value;
- // if (toValue / 1024 >= 0.9) {
- // toValue = toValue / 1024;
- // toUnit = 'KB';
- // }
- // if (toValue / 1024 >= 0.9) {
- // toValue = toValue / 1024;
- // toUnit = 'MB';
- // }
+ static formatMemory(value: number | string): string {
+ let unit = 'MB';
+ let toValue = +value;
+
if (toValue / 1024 >= 0.9) {
toValue = toValue / 1024;
- toUnit = 'GB';
+ unit = 'GB';
}
+
if (toValue / 1024 >= 0.9) {
toValue = toValue / 1024;
- toUnit = 'TB';
+ unit = 'TB';
}
+
if (toValue / 1024 >= 0.9) {
toValue = toValue / 1024;
- toUnit = 'PB';
+ unit = 'PB';
}
- return toValue.toFixed(1) + ' ' + toUnit;
+
+ return `${toValue.toFixed(1)} ${unit}`;
+ }
+
+ static isEmpty(arg: object | any[]): boolean {
+ return Object.keys(arg).length === 0;
+ }
+
+ static formatCount(value: number | string): string {
+ const unit = 'K';
+ const toValue = +value;
+
+ if (toValue >= 1000) {
+ return `${(toValue / 1000).toFixed(1)} ${unit}`;
+ }
+
+ return toValue.toString();
}
}