Skip to content

Commit 87900a3

Browse files
committed
Add UI to view and download usage records
1 parent 37bb24f commit 87900a3

File tree

9 files changed

+1147
-32
lines changed

9 files changed

+1147
-32
lines changed

api/src/main/java/org/apache/cloudstack/api/command/admin/usage/GenerateUsageRecordsCmd.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,13 @@ public class GenerateUsageRecordsCmd extends BaseCmd {
4949

5050
@Parameter(name = ApiConstants.END_DATE,
5151
type = CommandType.DATE,
52-
required = true,
52+
required = false,
5353
description = "End date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-03.")
5454
private Date endDate;
5555

5656
@Parameter(name = ApiConstants.START_DATE,
5757
type = CommandType.DATE,
58-
required = true,
58+
required = false,
5959
description = "Start date range for usage record query. Use yyyy-MM-dd as the date format, e.g. startDate=2009-06-01.")
6060
private Date startDate;
6161

ui/public/locales/en.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,7 @@
594594
"label.data.disk.offering": "Data disk offering",
595595
"label.date": "Date",
596596
"label.day": "Day",
597+
"label.days": "Days",
597598
"label.day.of.month": "Day of month",
598599
"label.day.of.week": "Day of week",
599600
"label.db.usage.metrics": "DB/Usage server",
@@ -773,6 +774,7 @@
773774
"label.done": "Done",
774775
"label.down": "Down",
775776
"label.download": "Download",
777+
"label.download.csv": "Download CSV",
776778
"label.download.kubeconfig.cluster": "Download kubeconfig for the cluster <br><br> The <code><b>kubectl</b></code> command-line tool uses kubeconfig files to find the information it needs to choose a cluster and communicate with the API server of a cluster.",
777779
"label.download.kubectl": "Download <code><b>kubectl</b></code> tool for cluster's Kubernetes version",
778780
"label.download.kubernetes.cluster.config": "Download Kubernetes cluster config",
@@ -886,6 +888,7 @@
886888
"label.featured": "Featured",
887889
"label.fetch.instances": "Fetch Instances",
888890
"label.fetch.latest": "Fetch latest",
891+
"label.fetched": "Fetched",
889892
"label.files": "Alternate files to retrieve",
890893
"label.filter": "Filter",
891894
"label.filter.annotations.all": "All comments",
@@ -1176,6 +1179,8 @@
11761179
"label.label": "Label",
11771180
"label.last.updated": "Last update",
11781181
"label.lastannotated": "Last annotation date",
1182+
"label.lastheartbeat": "Last heartbeat",
1183+
"label.lastsuccessfuljob": "Last successful job",
11791184
"label.lastboottime": "Boot time of the management server machine",
11801185
"label.lastname": "Last name",
11811186
"label.lastname.lower": "lastname",
@@ -1450,6 +1455,7 @@
14501455
"label.of": "of",
14511456
"label.of.month": "of month",
14521457
"label.offerha": "Offer HA",
1458+
"label.offeringid": "Offering ID",
14531459
"label.offeringtype": "Compute offering type",
14541460
"label.ok": "OK",
14551461
"label.only.end.date.and.time": "Only end date and time",
@@ -1654,7 +1660,14 @@
16541660
"label.rados.secret": "RADOS secret",
16551661
"label.rados.user": "RADOS user",
16561662
"label.ram": "RAM",
1663+
"label.range.today": "Today",
1664+
"label.range.yesterday": "Yesterday",
1665+
"label.range.last.1week": "Last 1 week",
1666+
"label.range.last.2week": "Last 2 weeks",
1667+
"label.range.last.1month": "Last 1 month",
1668+
"label.range.last.3month": "Last 3 months",
16571669
"label.raw.data": "Raw data",
1670+
"label.rawusage": "Raw usage (in hours)",
16581671
"label.rbd": "RBD",
16591672
"label.rbdid": "Cephx user",
16601673
"label.rbdmonitor": "Ceph monitor",
@@ -1887,6 +1900,7 @@
18871900
"label.sharedrouteripv6": "IPv6 address for the VR in this shared Network.",
18881901
"label.sharewith": "Share with",
18891902
"label.showing": "Showing",
1903+
"label.show.usage.records": "Show usage records",
18901904
"label.shrinkok": "Shrink OK",
18911905
"label.shutdown": "Shutdown",
18921906
"label.shutdown.provider": "Shutdown provider",
@@ -2183,8 +2197,20 @@
21832197
"label.upload.volume.from.url": "Upload volume from URL",
21842198
"label.url": "URL",
21852199
"label.usage.explanation": "Note: Only the usage server that owns the active usage job is shown here.",
2200+
"label.usage.records": "Usage records",
2201+
"label.usage.records.downloading": "Downloading usage records",
2202+
"label.usage.records.fetch.child.domains": "Fetch usage records for child domains",
2203+
"label.usage.records.usagetype.required": "Usage type is required with resource ID",
2204+
"label.usage.records.generate": "Generate usage records",
2205+
"label.usage.records.generate.description": "This will generate records only if there any records to be generated. i.e if the scheduled usage job was not run or failed",
2206+
"label.usage.records.purge": "Purge usage records",
2207+
"label.usage.records.purge.days": "Purge records older than",
2208+
"label.usage.records.purge.days.description": "Purge records older than the specified number of days.",
2209+
"label.usage.records.purge.alert": "Purging usage records will permanently delete the records from the database. Depending on the data being deleted, this can increase load on the database and may take a while. Are you sure you want to continue?",
2210+
"label.usageid": "Resource ID",
21862211
"label.usageinterface": "Usage interface",
21872212
"label.usagename": "Usage type",
2213+
"label.usagetype": "Usage type",
21882214
"label.usageunit": "Unit",
21892215
"label.usageislocal": "A Usage Server is installed locally",
21902216
"label.usagetypedescription": "Usage description",

ui/src/components/view/ListView.vue

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@
9898
<template v-if="column.key === 'templatetype'">
9999
<span>{{ text }}</span>
100100
</template>
101+
<template v-if="column.key === 'templateid'">
102+
<router-link :to="{ path: '/template/' + record.templateid }">{{ text }}</router-link>
103+
</template>
101104
<template v-if="column.key === 'type'">
102105
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(text)">{{ $t(text.toLowerCase()) }}</span>
103106
<span v-else>{{ text }}</span>
@@ -164,7 +167,7 @@
164167
<router-link :to="{ path: createPathBasedOnVmType(record.vmtype, record.virtualmachineid) }">{{ text }}</router-link>
165168
</template>
166169
<template v-if="column.key === 'virtualmachinename'">
167-
<router-link :to="{ path: getVmRouteUsingType(record) + record.virtualmachineid }">{{ text }}</router-link>
170+
<router-link :to="{ path: getVmRouteUsingType(record) + record.virtualmachineid }">{{ text ? text : record.name }}</router-link>
168171
</template>
169172
<template v-if="column.key === 'volumename'">
170173
<router-link :to="{ path: '/volume/' + record.volumeid }">{{ text }}</router-link>
@@ -244,7 +247,7 @@
244247
</template>
245248
<template v-if="column.key === 'vpcname'">
246249
<a v-if="record.vpcid">
247-
<router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text }}</router-link>
250+
<router-link :to="{ path: '/vpc/' + record.vpcid }">{{ text || record.vpcid }}</router-link>
248251
</a>
249252
<span v-else>{{ text }}</span>
250253
</template>
@@ -275,6 +278,9 @@
275278
<template v-if="column.key === 'level'">
276279
<router-link :to="{ path: '/event/' + record.id }">{{ text }}</router-link>
277280
</template>
281+
<template v-if="column.key === 'usageType'">
282+
{{ usageTypeMap[record.usagetype] }}
283+
</template>
278284

279285
<template v-if="column.key === 'clustername'">
280286
<router-link :to="{ path: '/cluster/' + record.clusterid }">{{ text }}</router-link>
@@ -318,7 +324,7 @@
318324
<span v-else>{{ text }}</span>
319325
</template>
320326
<template v-if="column.key === 'zone'">
321-
<router-link v-if="record.zoneid && !record.zoneid.includes(',') && $router.resolve('/zone/' + record.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + record.zoneid }">{{ text }}</router-link>
327+
<router-link v-if="record.zoneid && !record.zoneid.includes(',') && $router.resolve('/zone/' + record.zoneid).matched[0].redirect !== '/exception/404'" :to="{ path: '/zone/' + record.zoneid }">{{ text || record.zoneid }}</router-link>
322328
<span v-else>{{ text }}</span>
323329
</template>
324330
<template v-if="column.key === 'zonename'">
@@ -367,6 +373,9 @@
367373
<template v-if="['startdate', 'enddate'].includes(column.key) && ['vm', 'vnfapp'].includes($route.path.split('/')[1])">
368374
{{ getDateAtTimeZone(text, record.timezone) }}
369375
</template>
376+
<template v-if="['startdate', 'enddate'].includes(column.key) && ['usage'].includes($route.path.split('/')[1])">
377+
{{ $toLocaleDate(text.replace('\'T\'', ' ')) }}
378+
</template>
370379
<template v-if="column.key === 'order'">
371380
<div class="shift-btns">
372381
<a-tooltip :name="text" placement="top">
@@ -443,6 +452,13 @@
443452
icon="reload-outlined"
444453
:disabled="!('updateConfiguration' in $store.getters.apis)" />
445454
</template>
455+
<template v-if="column.key === 'usageActions'">
456+
<tooltip-button
457+
:tooltip="$t('label.view')"
458+
icon="search-outlined"
459+
@onClick="$emit('view-usage-record', record)" />
460+
<slot></slot>
461+
</template>
446462
<template v-if="column.key === 'tariffActions'">
447463
<tooltip-button
448464
:tooltip="$t('label.edit')"
@@ -573,9 +589,13 @@ export default {
573589
notification: 'storageallocatedthreshold',
574590
disable: 'storageallocateddisablethreshold'
575591
}
576-
}
592+
},
593+
usageTypeMap: {}
577594
}
578595
},
596+
created () {
597+
this.getUsageTypes()
598+
},
579599
computed: {
580600
hasSelected () {
581601
return this.selectedRowKeys.length > 0
@@ -895,6 +915,24 @@ export default {
895915
case 'SecondaryStorageVm': return '/systemvm/'
896916
default: return '/vm/'
897917
}
918+
},
919+
getUsageTypes () {
920+
if (this.$route.path.split('/')[1] === 'usage') {
921+
api('listUsageTypes').then(json => {
922+
if (json && json.listusagetypesresponse && json.listusagetypesresponse.usagetype) {
923+
this.usageTypes = json.listusagetypesresponse.usagetype.map(x => {
924+
return {
925+
id: x.usagetypeid,
926+
value: x.description
927+
}
928+
})
929+
this.usageTypeMap = {}
930+
for (var usageType of this.usageTypes) {
931+
this.usageTypeMap[usageType.id] = usageType.value
932+
}
933+
}
934+
})
935+
}
898936
}
899937
}
900938
}

ui/src/config/router.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,17 @@ export function asyncRouterMap () {
221221
generateRouterMap(offering),
222222
generateRouterMap(config),
223223
generateRouterMap(tools),
224+
{
225+
path: '/usage',
226+
name: 'usage',
227+
title: 'label.usage.records',
228+
icon: 'ContainerOutlined',
229+
permission: ['listUsageRecords'],
230+
meta: { title: 'label.usage.records', icon: 'ContainerOutlined' },
231+
component: () => import('@/views/infra/UsageRecords.vue')
232+
},
224233
generateRouterMap(quota),
225234
generateRouterMap(cloudian),
226-
227235
{
228236
path: '/exception',
229237
name: 'exception',

0 commit comments

Comments
 (0)