[Ovirt 노트] 계기판의 실현 분석과 정리
우리 중의 한 사람으로서 끊임없는 학습이 필요합니다. 저는 업무의 여가 시간에 분석과 정리, 학습 노트를 블로그로 작성하여 여러분과 함께 교류하고 이런 방식으로 자신의 학습 여행을 기록하고 싶습니다.
본고는 학습 교류에만 사용되기 때문에 권리 침해는 반드시 삭제해야 한다.상업 목적에 사용하지 않으니 전재는 출처를 밝혀 주십시오.
분석 및 정리된 버전은 Ovirt 4.2.3 버전입니다.
PluginDefinitions
클래스는 플러그인 프로필의 정보 읽기(계기판의 프로필 위치/usr/share/ovirt-engine/ui-plugins/dashboard.json)를 실현했다.[root@localhost ui-plugins]# cat dashboard.json
{
"name": "dashboard",
"url": "plugin/dashboard/plugin.html",
"resourcePath": "dashboard-resources",
"lazyLoad": false
}
등록 정보
설명
name
플러그인 이름
url
플러그인 포털 주소
resourcePath
자원 경로
lazyLoad
로드 지연 여부
PluginManager
클래스는 플러그인 데이터 정보를 읽는 것을 실현했고 exposePluginApi
방법을 통해Javascript를 호출하여pluginapi 대상을 만들었다.1. 호출 실현
속성 구성
설명
title
html 파일의 제목을 생성합니다.
filename
html 파일의 파일 이름입니다. 기본값은 index입니다.html.
template
템플릿 이름, 템플릿 유형은 html,jade,ejs 등이 가능합니다.
inject
true(기본값, script 라벨은 html 파일의 바디 밑에 있음), 바디(script 라벨은 html 파일의 바디 밑에 있음), 헤드(script 라벨은 html 파일의 헤드에 있음), false(생성된 js 파일을 삽입하지 않음)
favicon
favicon을 생성합니다. 값은 경로입니다.
minify
미니fy를 사용하여 생성된 html 파일을 압축합니다.기본값은 false입니다.
cache
기본true, 내용이 바뀔 때 새 파일을 생성합니다.
showErrors
웹 패키지가 잘못 보고되었을 때, 오류 정보를 pre에 감싸십시오. 기본값은true입니다.
chunks
여러 개의 입구 파일이 있고, 컴파일된 후에 여러 개의 포장된 파일을 생성하면,chunks는 어떤 js 파일을 사용할 것인지 선택할 수 있습니다.기본적으로 모두 표시됩니다.
excludeChunks
일부 js를 배제합니다.
xhtml
xhtml 모드 인용 파일을 호환할지 여부입니다.기본값은 false입니다.
chunksSortMode
script의 순서,none,auto,dependency,{function}
new HtmlWebpackPlugin({
filename: 'main-tab.html',
template: 'static/html/main-tab.template.ejs',
inject: true,
chunks: ['vendor', 'main-tab']
}),
new HtmlWebpackPlugin({
filename: 'plugin.html',
template: 'static/html/plugin.template.ejs',
inject: true,
chunks: ['vendor', 'plugin']
}),
[root@localhost dashboard-resources]# cat plugin.html
getPluginApi().register({
UiInit () {
// add Dashboard main tab
getPluginApi().addPrimaryMenuPlace(msg.mainTabTitle(), dashboardPlaceToken, `${pluginBasePath}/main-tab.html`, {
// position this tab before any standard ones
priority: -1,
// customize the prefix displayed in search bar
searchPrefix: 'Dashboard',
defaultPlace: true,
icon: 'fa-tachometer'
})
}
})
getPluginApi
plugin-api.js 파일에 정의되어 있습니다.PluginManager
류의 exposePluginApi
방법에서 이미 실현되었다.const getPluginApi = () => {
api = api || getWebAdminWindow().pluginApi(pluginName)
return api
}
pluginApi.fn = pluginApi.prototype = {
pluginName: null, // Initialized in constructor function
// Constructor function
init: function(pluginName) {
this.pluginName = pluginName;
return this;
},
......
// Give init function the pluginApi prototype for later instantiation
pluginApi.fn.init.prototype = pluginApi.fn;
exposePluginApi
방법에서 ready
방법을 실현했고 실제PluginManager
류의 pluginReady
방법을 호출했다.getPluginApi
의UiInit
방법이다.// Indicates that the plugin is ready for use
ready: function() {
[email protected]::pluginReady(Ljava/lang/String;)(this.pluginName);
},
// Initialize the plugin once it's ready
initPlugin(plugin);
if (invokePlugin(plugin, "UiInit", null)) { //$NON-NLS-1$
UiInit
방법에main-tab을 불러왔습니다.html 페이지, 인터페이스에main-tab이 추가되었습니다.jsx. import DashboardDataProvider from './components/DashboardDataProvider'
import GlobalDashboard from './components/GlobalDashboard'
1.1 파일 설명
1.1.1 DashboardDataProvider
_fetchData () {
const request = this._jqXHR = $.ajax({
method: 'GET',
url: `${getPluginApi().engineBaseUrl()}webadmin/dashboard_data`,
dataType: 'json',
headers: {
'Accept': 'application/json'
// For testing purposes you can uncomment either of these.
// 'Prefer': 'fake_data' // returns randomly generated data
// 'Prefer': 'error' // triggers HTTP error response
}
})
request.done((data) => {
this._updateData({ data: this._transformData({ data }) })
})
request.fail(() => {
console.error('Request failed', request)
this._updateData({ data: DATA_ERROR })
})
}
dashboardData
org.ovirt.engine.ui.frontend.server.dashboard.DashboardDataServlet
100
dashboardData
/dashboard_data
/*
* Update the utilization cache now and every 5 minutes (by default) thereafter, but never run 2 updates simultaneously.
*/
try {
UTILIZATION_CACHE_UPDATE_INTERVAL = config.getLong(UTILIZATION_CACHE_UPDATE_INTERVAL_KEY);
} catch (IllegalArgumentException e) {
log.error("Missing/Invalid key \"{}\", using default value of 300", UTILIZATION_CACHE_UPDATE_INTERVAL_KEY, e); //$NON-NLS-1$
UTILIZATION_CACHE_UPDATE_INTERVAL = 300;
}
utilizationCacheUpdate = scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
Logger log = LoggerFactory.getLogger(DashboardDataServlet.class.getName() + ".CacheUpdate.Utilization"); //$NON-NLS-1$
@Override
public void run() {
log.trace("Attempting to update the Utilization cache"); //$NON-NLS-1$
try {
populateUtilizationCache();
} catch (DashboardDataException e) {
log.error("Could not update the Utilization Cache: {}", e.getMessage(), e); //$NON-NLS-1$
}
}
}, 0, UTILIZATION_CACHE_UPDATE_INTERVAL, TimeUnit.SECONDS);
log.info("Dashboard utilization cache updater initialized (update interval {}s)", UTILIZATION_CACHE_UPDATE_INTERVAL); //$NON-NLS-1$
try {
INVENTORY_CACHE_UPDATE_INTERVAL = config.getLong(INVENTORY_CACHE_UPDATE_INTERVAL_KEY);
} catch (IllegalArgumentException e) {
log.error("Missing/Invalid key \"{}\", using default value of 60", INVENTORY_CACHE_UPDATE_INTERVAL_KEY, e); //$NON-NLS-1$
INVENTORY_CACHE_UPDATE_INTERVAL = 60;
}
inventoryCacheUpdate = scheduledExecutor.scheduleWithFixedDelay(new Runnable() {
Logger log = LoggerFactory.getLogger(DashboardDataServlet.class.getName() + ".CacheUpdate.Inventory"); //$NON-NLS-1$
@Override
public void run() {
log.trace("Attempting to update the Inventory cache"); //$NON-NLS-1$
try {
populateInventoryCache();
} catch (DashboardDataException e) {
log.error("Could not update the Inventory Cache: {}", e.getMessage(), e); //$NON-NLS-1$
}
}
}, 0, INVENTORY_CACHE_UPDATE_INTERVAL, TimeUnit.SECONDS);
log.info("Dashboard inventory cache updater initialized (update interval {}s)", INVENTORY_CACHE_UPDATE_INTERVAL); //$NON-NLS-1$
1.1.1 데이터 소스 연결 가져오기
@Resource(mappedName = "java:/DWHDataSource")
private DataSource dwhDataSource;
@Resource(mappedName = "java:/ENGINEDataSource")
private DataSource engineDataSource;
설명
ClusterDwhDAO.properties
dwh 라이브러리의 클러스터 관련 통계 SQL.
ClusterEngineDAO.properties
engin e라이브러리 클러스터 관련 통계 SQL.
GlusterVolumeEngineDAO.properties
engin e라이브러리의 볼륨 관련 통계 SQL.
HostDwhDAO.properties
dwh 라이브러리의 호스트 관련 통계 SQL.
HostEngineDAO.properties
engine 라이브러리의 호스트 관련 통계 SQL.
StorageDomainDwhDAO.properties
dwh 라이브러리의 저장소 도메인 관련 통계 SQL입니다.
StorageDomainEngineDAO.properties
engin e라이브러리의 스토리지 도메인 관련 통계 SQL
VmDwhDAO.properties
dwh 라이브러리의 VM 관련 통계 SQL.
VmEngineDAO.properties
engine 라이브러리에서 가상 머신 관련 통계 SQL.
host.hourly_cpu_mem_history=SELECT \
the_datetime AS the_date, \
SUM(a.cpu_usage_per_host) / SUM(a.total_host_cpu_cores) AS cpu_avg, \
SUM(a.memory_usage_per_host) / SUM(a.total_host_mem_avg) AS mem_avg \
FROM \
( \
SELECT \
date_trunc('hour',hourly.history_datetime) AS the_date, \
hosts.host_id, \
AVG(COALESCE(hourly.cpu_usage_percent, 0) * number_of_cores ) AS cpu_usage_per_host, \
AVG(COALESCE(hourly.memory_usage_percent, 0) * memory_size_mb ) AS memory_usage_per_host , \
AVG(COALESCE (hosts.number_of_cores , 0 )) AS total_host_cpu_cores, \
AVG(COALESCE (hosts.memory_size_mb , 0 ) )AS total_host_mem_avg \
FROM \
v4_2_statistics_hosts_resources_usage_hourly hourly \
INNER JOIN \
v4_2_configuration_history_hosts hosts \
ON \
hosts.host_id = hourly.host_id \
WHERE \
/*Here we filter by active hosts only*/ \
hourly.host_status = 1 AND \
/*Here we join the configrations of the hosts with the statistics*/ \
hourly.host_configuration_version = hosts.history_id AND \
/*Here we filter by the last 24 hours period*/ \
history_datetime >= date_trunc('hour',CURRENT_TIMESTAMP) - INTERVAL '24 hours' AND \
history_datetime <= date_trunc('hour',CURRENT_TIMESTAMP) + INTERVAL '2 hours' \
GROUP BY \
hourly.history_datetime, hosts.host_id \
......
1.1.2 재고 정보
private static final String DC_INVENTORY = "datacenter.inventory"; //$NON-NLS-1$
public static InventoryStatus getDcInventoryStatus(DataSource engineDataSource) throws DashboardDataException {
DataCenterDao dao = new DataCenterDao(engineDataSource);
return dao.getDcInventoryStatus();
}
private static final String CLUSTER_INVENTORY = "cluster.inventory"; //$NON-NLS-1$
public static InventoryStatus getClusterInventoryStatus(DataSource engineDataSource) throws DashboardDataException {
ClusterEngineDao dao = new ClusterEngineDao(engineDataSource);
return dao.getClusterInventorySummary();
}
private static final String HOST_INVENTORY = "host.inventory"; //$NON-NLS-1$
public static InventoryStatus getHostInventoryStatus(DataSource engineDataSource) throws DashboardDataException {
HostEngineDao dao = new HostEngineDao(engineDataSource);
return dao.getHostInventoryStatus();
}
private static final String STORAGE_INVENTORY = "storage.inventory"; //$NON-NLS-1$
public static InventoryStatus getStorageInventoryStatus(DataSource engineDataSource) throws DashboardDataException {
StorageDomainEngineDao dao = new StorageDomainEngineDao(engineDataSource);
return dao.getStorageInventoryStatus();
}
private static final String VM_INVENTORY = "vm.inventory"; //$NON-NLS-1$
public static InventoryStatus getVmInventorySummary(DataSource engineDataSource) throws DashboardDataException {
VmEngineDao dao = new VmEngineDao(engineDataSource);
return dao.getVmInventoryStatus();
}
private static final String GLUSTER_VOLUME_INVENTORY = "glusterVolume.inventory"; //$NON-NLS-1$
public static InventoryStatus getGlusterVolumeInventorySummary(DataSource engineDataSource)
throws DashboardDataException {
GlusterVolumeEngineDao dao = new GlusterVolumeEngineDao(engineDataSource);
return dao.getVolumeInventoryStatus();
}
1.1.3 글로벌 활용도
1.1.3.1 CPU 및 메모리 정보
HourlySummaryHelper.getCpuMemSummary(utilization, dwhDataSource);
private static final String TOTAL_CPU_MEMORY_COUNT = "host.total_cpu_memory_count"; //$NON-NLS-1$
private static void getTotalCpuMemCount(GlobalUtilizationResourceSummary cpuSummary,
GlobalUtilizationResourceSummary memSummary, DataSource dwhDataSource) throws DashboardDataException {
HostDwhDao dao = new HostDwhDao(dwhDataSource);
ResourcesTotal total = dao.getTotalCpuMemCount();
cpuSummary.setPhysicalTotal(total.getCpuTotal());
//Transform MB to GB.
memSummary.setPhysicalTotal(total.getMemTotal() / 1024);
}
private static final String HOURLY_CPU_MEM_HISTORY = "host.hourly_cpu_mem_history"; //$NON-NLS-1$
private static void getHourlyCpuMemUsage(GlobalUtilizationResourceSummary cpuSummary,
GlobalUtilizationResourceSummary memSummary, DataSource dataSource) throws DashboardDataException {
List cpuHistory = new ArrayList<>();
List memHistory = new ArrayList<>();
HostDwhDao dao = new HostDwhDao(dataSource);
List history = dao.getHourlyCpuMemUsage();
for (ResourceUsage item: history) {
cpuHistory.add(new HistoryNode(item.getEpoch(), item.getCpuValue()));
memHistory.add(new HistoryNode(item.getEpoch(), item.getMemValue() * memSummary.getTotal() / 100));
}
ResourceUsage last5minUsage = dao.getLast5MinCpuMemUsage();
cpuSummary.setUsed(last5minUsage.getCpuValue());
memSummary.setUsed(last5minUsage.getMemValue() * memSummary.getTotal() / 100);
cpuSummary.setHistory(cpuHistory);
memSummary.setHistory(memHistory);
}
private static final String VIRTUAL_CPU_MEMORY_COUNT = "vm.virtual_cpu_memory_count"; //$NON-NLS-1$
private static void getVirtualCpuMemCount(GlobalUtilizationResourceSummary cpuSummary,
GlobalUtilizationResourceSummary memSummary, DataSource dwhDataSource) throws DashboardDataException {
VmDwhDao dao = new VmDwhDao(dwhDataSource);
ResourcesTotal resourcesTotal = dao.getVirtualCpuMemCount();
cpuSummary.setVirtualTotal(resourcesTotal.getCpuTotal());
cpuSummary.setVirtualUsed(resourcesTotal.getCpuUsed());
memSummary.setVirtualTotal(resourcesTotal.getMemTotal());
memSummary.setVirtualUsed(resourcesTotal.getMemUsed());
}
1.1.3.2 정보 저장
utilization.setStorage(HourlySummaryHelper.getStorageSummary(dwhDataSource));
private static final String TOTAL_STORAGE_COUNT = "storage.total_count"; //$NON-NLS-1$
private static Double getTotalStorageCount(DataSource dwhDataSource) throws DashboardDataException {
StorageDomainDwhDao dao = new StorageDomainDwhDao(dwhDataSource);
//Transform GB to TB.
return dao.getTotalStorageCount() / 1024;
}
private static final String HOURLY_STORAGE_HISTORY = "storage.hourly_history"; //$NON-NLS-1$
private static List getHourlyStorageHistory(DataSource dwhDataSource) throws DashboardDataException {
List history = new ArrayList<>();
StorageDomainDwhDao dao = new StorageDomainDwhDao(dwhDataSource);
List usageList = dao.getHourlyStorageHistory();
for (ResourceUsage usage: usageList) {
//Transform GB to TB.
history.add(new HistoryNode(usage.getEpoch(), usage.getStorageValue() / 1024));
}
return history;
}
private static final String LAST5_MIN_STORAGE_AVERAGE = "storage.last5_minutes_average"; //$NON-NLS-1$
private static double getLast5MinutesStorageAverage(DataSource dwhDataSource) throws DashboardDataException {
StorageDomainDwhDao dao = new StorageDomainDwhDao(dwhDataSource);
//Transform GB to TB.
return dao.getLast5MinutesStorageAverage() / 1024;
}
1.1.4 클러스터 활용도
private static final String CLUSTER_LAST_24_AVERAGE = "cluster.last24hours"; //$NON-NLS-1$
public static void getCpuAndMemory(HeatMapData utilization, DataSource dataSource) throws DashboardDataException {
ClusterDwhDao dao = new ClusterDwhDao(dataSource);
List averages = dao.getClusterCpuAndMemoryAverage();
List cpu = new ArrayList<>();
List memory = new ArrayList<>();
for (ClusterResourceAverage data: averages) {
cpu.add(new HeatMapBlock(data.getName(), data.getCpuAverage()));
memory.add(new HeatMapBlock(data.getName(), data.getMemoryAverage()));
}
utilization.setCpu(cpu);
utilization.setMemory(memory);
}
1.1.1.5 스토리지 활용도
private static final String STORAGE_LAST24_AVERAGE = "storage.last24hours_average"; //$NON-NLS-1$
public static List getStorage(DataSource dwhDataSource) throws DashboardDataException {
List nodes = new ArrayList<>();
StorageDomainDwhDao dao = new StorageDomainDwhDao(dwhDataSource);
for (StorageDomainAverage data: dao.getStorageAverage()) {
nodes.add(new HeatMapBlock(data.getName(), data.getValue()));
}
return nodes;
}
1.1.2 GlobalDashboard
import RefreshDataControl from './RefreshDataControl'
import LastUpdatedLabel from './LastUpdatedLabel'
import AggregateStatusCard from './AggregateStatusCard'
import UtilizationTrendCard from './UtilizationTrendCard'
import HeatMapLegend from './patternfly/HeatMapLegend'
import HeightMatching from './helper/HeightMatching'
{/* refresh buttons and last updated information label */}
{/* inventory cards - match height of all of the card's titles and body */}
{
applySearch(webadminPlaces.dc, searchPrefixes.dc)
}}
onStatusCountClick={(statusItem) => {
applySearch(webadminPlaces.dc, searchPrefixes.dc, [{
name: searchFields.status,
values: statusItem.statusValues
}])
}} />
......
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.