442 lines
13 KiB
Vue
442 lines
13 KiB
Vue
<template>
|
|
<div class="row md12 justify--space-between">
|
|
<va-input
|
|
class="flex mb-1"
|
|
placeholder="Search..."
|
|
v-model="filterTmp"
|
|
@keyup="clickFilterEnter"
|
|
:bordered="false"
|
|
>
|
|
<template #prependInner class="row">
|
|
<va-icon class="material-icons" color="secondary">search</va-icon>
|
|
</template>
|
|
|
|
<template #appendInner class="row">
|
|
<va-chip
|
|
v-for="(item, index) in this.filters"
|
|
class="ml-2 filterTag"
|
|
size="small"
|
|
>
|
|
{{ item }}
|
|
<va-button icon="clear" size="small" class="ml-1 mr-0" @click="clickFilterClear(index)" />
|
|
</va-chip>
|
|
</template>
|
|
</va-input>
|
|
|
|
<div class="flex mb-1">
|
|
<va-button
|
|
@click="updateReport"
|
|
class="update_btn mr-2"
|
|
flat
|
|
>
|
|
<va-icon
|
|
name="loop"
|
|
:spin="isLoading"
|
|
/>
|
|
</va-button>
|
|
<va-button
|
|
class="justify--end mr-2"
|
|
outline
|
|
icon="save_alt"
|
|
@click="clickCSV(this.filteredItems, this.columns)"
|
|
>
|
|
CSV
|
|
</va-button>
|
|
<va-button-dropdown
|
|
class="justify--end mr-2"
|
|
outline
|
|
label="Columns"
|
|
:close-on-content-click="false"
|
|
>
|
|
<div>
|
|
<va-checkbox class="mb-2" v-for="(item, index) in this.columnsAll" :label="item.label" v-model="this.columnsAll[index].visible" @update:model-value="calcColumns" />
|
|
</div>
|
|
</va-button-dropdown>
|
|
</div>
|
|
</div>
|
|
<va-data-table
|
|
:items="items"
|
|
:columns="columns"
|
|
:filter="filter"
|
|
:hoverable="true"
|
|
@filtered="filteredItems = $event.items"
|
|
:loading="isLoading"
|
|
sticky-header
|
|
class="flex md12 tableReport"
|
|
:row-bind="getRowBind"
|
|
>
|
|
<template #cell(vcenter_hostname)="{ value }">
|
|
<a :href="`https://${ value }/ui`" target="_blank" class="link">{{ value }}</a>
|
|
</template>
|
|
|
|
<template #cell(environment)="{ value,rowData }">
|
|
<va-badge right :text="value" :color="rowData.environment.attributes?.color"/>
|
|
</template>
|
|
|
|
<template #cell(hosts)="{ value,rowData }">
|
|
|
|
<va-badge right color="warning" v-if="rowData.maintenance.length > 0">
|
|
<template #text>
|
|
<router-link :to="{ name:'vmware-mmhosts', params: { filters: [`cluster/${rowData.attributes.cluster_name.toLowerCase()}`] } }">{{ rowData.maintenance.length }}</router-link>
|
|
</template>
|
|
<span class="fixedWidth2ch">{{ value }}</span>
|
|
</va-badge>
|
|
<span v-else>{{ value }}</span>
|
|
|
|
</template>
|
|
|
|
<template #cell(hosts_maintenance)="{ value,rowData }">
|
|
{{ rowData.maintenance.length }}
|
|
</template>
|
|
|
|
<template #cell(cpu_cap_use)="{ value }" >
|
|
{{ value }}%
|
|
</template>
|
|
|
|
<template #cell(pcpu_retire_target)="{ value }" >
|
|
{{ value*100 }}%
|
|
</template>
|
|
|
|
</va-data-table>
|
|
<va-alert class="mt-3" color="info" outline>
|
|
<div class="row md-12 justify--space-between reportFooter">
|
|
<span>
|
|
Number of filtered items:
|
|
<va-chip>{{ filteredItems.length }}</va-chip>
|
|
</span>
|
|
<span class="reportDate mr-3">
|
|
<va-badge right class="transparentBadge dangerBadge">
|
|
<template #text v-if="checkReportDate(this.timestamp)">
|
|
<va-icon name="warning_amber_icon" />
|
|
</template>
|
|
Data collected: {{ timestamp }}
|
|
</va-badge>
|
|
</span>
|
|
</div>
|
|
</va-alert>
|
|
</template>
|
|
|
|
<script>
|
|
import { defineComponent } from 'vue';
|
|
import ReportsService from '@/api/report-service';
|
|
import { sortingBase } from '@/scripts/sorters';
|
|
import { formatBytes, pickClass, checkReportDate } from '@/scripts/formatters';
|
|
import { clickCSV } from '@/scripts/exporters';
|
|
|
|
export default defineComponent({
|
|
data () {
|
|
const columnsAll = [
|
|
{
|
|
key: 'attributes.contour_name',
|
|
label: 'Contour',
|
|
sortable: true,
|
|
visible: true,
|
|
},
|
|
{
|
|
key: 'attributes.vcenter_hostname',
|
|
label: 'vCenter',
|
|
sortable: true,
|
|
name: 'vcenter_hostname',
|
|
},
|
|
{
|
|
key: 'attributes.cluster_name',
|
|
label: 'Cluster',
|
|
sortable: true,
|
|
name: 'cluster',
|
|
visible: true,
|
|
},
|
|
{
|
|
key: 'attributes.environment_name',
|
|
label: 'Environment',
|
|
tdAlign: 'center',
|
|
thAlign: 'center',
|
|
sortable: true,
|
|
name: 'environment',
|
|
visible: true,
|
|
},
|
|
{
|
|
key: 'attributes.hosts_total',
|
|
label: 'Hosts',
|
|
sortable: true,
|
|
name: 'hosts',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
visible: true,
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.hosts_to_decomiss',
|
|
label: 'Hosts to decomission',
|
|
sortable: true,
|
|
name: 'hosts_to_decomiss',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
visible: true,
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.pcpu_to_decomiss',
|
|
label: 'pCPU to decomiss',
|
|
sortable: true,
|
|
name: 'pcpu_to_decomiss',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.hosts_staged_dcm',
|
|
label: 'Staged to decomission',
|
|
sortable: true,
|
|
name: 'hosts_staged_dcm',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
visible: true,
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'maintenance',
|
|
label: 'MM',
|
|
sortable: true,
|
|
name: 'hosts_maintenance',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.hosts_reserved',
|
|
label: 'Reserved',
|
|
sortable: true,
|
|
name: 'hosts_reserved',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.vms_total',
|
|
label: 'VMs',
|
|
sortable: true,
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
visible: true,
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.sockets_total',
|
|
label: 'Sockets',
|
|
sortable: true,
|
|
name: 'sockets_total',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.cpu_cap_used',
|
|
label: 'CPU provisioned',
|
|
sortable: true,
|
|
name: 'cpu_cap_use',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
visible: true,
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.pcpu_ovp_target',
|
|
label: 'CPU Target',
|
|
sortable: true,
|
|
name: 'pcpu_ovp_target',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.pcpu_ovp_current',
|
|
label: 'CPU Current',
|
|
sortable: true,
|
|
name: 'pcpu_ovp_current',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.pcpu_retire_target',
|
|
label: 'CPU Decomission target',
|
|
sortable: true,
|
|
name: 'pcpu_retire_target',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.pcpu_total',
|
|
label: 'pCPU Total',
|
|
sortable: true,
|
|
name: 'pcpu_total',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
{
|
|
key: 'attributes.vcpu_provisioned',
|
|
label: 'vCPU Provisioned',
|
|
sortable: true,
|
|
name: 'vcpu_provisioned',
|
|
sortingFn: (a,b) => this.sortingBase(a,b),
|
|
filterable: false,
|
|
},
|
|
]
|
|
|
|
return {
|
|
items: [],
|
|
itemsAll: [],
|
|
columns: [],
|
|
columnsAll,
|
|
filterTimeout: 0,
|
|
filterTmp: '',
|
|
filter: '',
|
|
filters: [],
|
|
isLoading: true,
|
|
filteredItems: [],
|
|
timestamp: 0,
|
|
showBlock: false,
|
|
};
|
|
},
|
|
|
|
created() {
|
|
if(localStorage.decomissionVisibleColumns) {
|
|
let visibleColumns = JSON.parse(localStorage.decomissionVisibleColumns)
|
|
|
|
this.columnsAll.forEach( item =>
|
|
visibleColumns.includes(item.key) ? item.visible = true : item.visible = false
|
|
)
|
|
} else {
|
|
localStorage.decomissionVisibleColumns = JSON.stringify(
|
|
this.columnsAll.filter(item => item.visible).map(a => a.key)
|
|
)
|
|
}
|
|
this.columns = this.columnsAll.filter(item => item.visible);
|
|
this.retreiveReport();
|
|
|
|
|
|
if (this.$route.params?.filters) {
|
|
this.filters = this.$route.params.filters
|
|
|
|
this.columnsAll[2].visible = true
|
|
}
|
|
|
|
this.columns = this.columnsAll.filter(item => item.visible);
|
|
},
|
|
|
|
methods: {
|
|
checkReportDate,
|
|
sortingBase,
|
|
formatBytes,
|
|
pickClass,
|
|
clickCSV,
|
|
|
|
calcColumns () {
|
|
localStorage.decomissionVisibleColumns = JSON.stringify(
|
|
this.columnsAll.filter(item => item.visible).map(a => a.key)
|
|
)
|
|
this.columns = this.columnsAll.filter(item => item.visible);
|
|
},
|
|
|
|
getRowBind (row) {
|
|
const classes = []
|
|
if (row.attributes.hosts_staged_dcm >= 16) {
|
|
classes.push('rowCritical')
|
|
}
|
|
return { class: classes }
|
|
},
|
|
|
|
clickFilterEnter (event) {
|
|
if ((event.keyCode > 111 && event.keyCode < 136) || (event.keyCode > 15 && event.keyCode < 19)) { return }
|
|
if (event.keyCode === 13) {
|
|
if (this.filterTmp !== '') {
|
|
this.filters.unshift(this.filterTmp.toLowerCase())
|
|
this.items = this.filterItems(this.items, this.filters)
|
|
this.filterTmp = ''
|
|
this.filter = ''
|
|
}
|
|
} else {
|
|
this.isLoading = true
|
|
clearTimeout(this.filterTimeout)
|
|
this.filterTimeout = setTimeout(() => {
|
|
this.filter = this.filterTmp
|
|
this.isLoading = false
|
|
},300)
|
|
}
|
|
},
|
|
|
|
clickFilterClear (index) {
|
|
this.filters.splice(index,1)
|
|
this.items = this.filterItems(this.itemsAll, this.filters)
|
|
},
|
|
|
|
filterItems(items, filters) {
|
|
filters.forEach(filter => {
|
|
items = items.filter(item => {
|
|
return Object.values(item.attributes).some( value => {
|
|
if (typeof value === 'string') {
|
|
return value.toLowerCase().includes(filter)
|
|
} else {
|
|
false
|
|
}
|
|
})
|
|
})
|
|
})
|
|
return items
|
|
},
|
|
|
|
retreiveReport() {
|
|
ReportsService.getLastFrame().then(response => {
|
|
this.timestamp = response?.attributes?.timestamp.slice(0,response.attributes.timestamp.length-10) ?? 0
|
|
|
|
ReportsService.getLastVmWareCapacityReport(response.id).then(response => {
|
|
let clusters = response.data.included.filter(x => x.type === "cluster");
|
|
let vcenters = response.data.included.filter(x => x.type === "vcenter");
|
|
let contours = response.data.included.filter(x => x.type === "contour");
|
|
let environments = response.data.included.filter(x => x.type === "environment");
|
|
let maintenance = response.data.included.filter(x => x.type === "maintenance");
|
|
|
|
response.data.data.forEach(element => {
|
|
element["cluster"] = clusters.find(x => x.id == element.attributes.cluster_id)
|
|
element["vcenter"] = vcenters.find(x => x.id == element.cluster?.attributes.vcenter_id)
|
|
element["contour"] = contours.find(x => x.id == element.vcenter?.attributes.contour_id)
|
|
element["environment"] = environments.find(x => x.id == element.cluster?.attributes.environment_id) ?? ""
|
|
element["maintenance"] = maintenance.filter(x => x.attributes.cluster_id == element.attributes.cluster_id) ?? 0
|
|
|
|
element.attributes["cluster_name"] = element.cluster?.attributes.name
|
|
element.attributes["contour_name"] = element.contour?.attributes.name
|
|
element.attributes["environment_name"] = element?.environment?.attributes?.name ?? ""
|
|
element.attributes["vcenter_hostname"] = element.vcenter?.attributes.hostname
|
|
|
|
var pcpu = ((element.attributes.pcpu_total*element.attributes.pcpu_retire_target | 0) - ((element.attributes.vcpu_provisioned/element.attributes.pcpu_ovp_target) | 0)) ?? 0
|
|
if (pcpu > 0) {
|
|
element.attributes["pcpu_to_decomiss"] = pcpu
|
|
} else {
|
|
element.attributes["pcpu_to_decomiss"] = 0
|
|
}
|
|
|
|
element.attributes["hosts_to_decomiss"] = (element.attributes?.pcpu_to_decomiss/(element.attributes.pcpu_host_max) | 0) ?? 0
|
|
|
|
|
|
delete element.attributes.cluster_id
|
|
delete element.attributes.frame_id
|
|
delete element.relationships
|
|
delete element.links
|
|
});
|
|
|
|
response.data.data = response.data.data.filter(item => item.attributes.contour_name != 'VDI')
|
|
|
|
this.items = this.filterItems(response.data.data, this.filters);
|
|
this.itemsAll = response.data.data;
|
|
|
|
this.isLoading = false
|
|
}).catch(e => {
|
|
console.log(e);
|
|
})
|
|
}).catch(e => {
|
|
console.log(e);
|
|
})
|
|
},
|
|
|
|
updateReport() {
|
|
this.isLoading = true
|
|
|
|
this.retreiveReport()
|
|
},
|
|
},
|
|
})
|
|
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
|
|
</style> |