]>
git.proxmox.com Git - pve-manager.git/blob - www/manager6/ceph/Services.js
1 Ext
.define('PVE.ceph.Services', {
2 extend
: 'Ext.panel.Panel',
3 alias
: 'widget.pveCephServices',
10 bodyPadding
: '0 5 20',
14 'text-align': 'center',
21 xtype
: 'pveCephServiceList',
23 title
: gettext('Monitors'),
27 xtype
: 'pveCephServiceList',
29 title
: gettext('Managers'),
33 xtype
: 'pveCephServiceList',
35 title
: gettext('Meta Data Servers'),
39 updateAll: function(metadata
, status
) {
42 const healthstates
= {
50 // order guarantee since es2020, but browsers did so before. Note, integers would break it.
51 const healthmap
= Object
.keys(healthstates
);
52 let maxversion
= "00.0.00";
53 Object
.values(metadata
.node
|| {}).forEach(function(node
) {
54 if (PVE
.Utils
.compare_ceph_versions(node
?.version
?.parts
, maxversion
) > 0) {
55 maxversion
= node
?.version
?.parts
;
58 var quorummap
= status
&& status
.quorum_names
? status
.quorum_names
: [];
59 let monmessages
= {}, mgrmessages
= {}, mdsmessages
= {};
62 Ext
.Object
.each(status
.health
.checks
, function(key
, value
, _obj
) {
63 if (!Ext
.String
.startsWith(key
, "MON_")) {
66 for (let i
= 0; i
< value
.detail
.length
; i
++) {
67 let match
= value
.detail
[i
].message
.match(/mon.([a-zA-Z0-9\-.]+)/);
72 if (!monmessages
[monid
]) {
73 monmessages
[monid
] = {
74 worstSeverity
: healthstates
.HEALTH_OK
,
79 let severityIcon
= PVE
.Utils
.get_ceph_icon_html(value
.severity
, true);
80 let details
= value
.detail
.reduce((acc
, v
) => `${acc}\n${v.message}`, '');
81 monmessages
[monid
].messages
.push(severityIcon
+ details
);
83 if (healthstates
[value
.severity
] < monmessages
[monid
].worstSeverity
) {
84 monmessages
[monid
].worstSeverity
= healthstates
[value
.severity
];
91 mgrmessages
[status
.mgrmap
.active_name
] = "active";
92 status
.mgrmap
.standbys
.forEach(function(mgr
) {
93 mgrmessages
[mgr
.name
] = "standby";
98 status
.fsmap
.by_rank
.forEach(function(mds
) {
99 mdsmessages
[mds
.name
] = 'rank: ' + mds
.rank
+ "; " + mds
.status
;
106 if (quorummap
.indexOf(mon
.name
) !== -1) {
107 mon
.health
= healthstates
.HEALTH_OK
;
109 mon
.health
= healthstates
.HEALTH_ERR
;
111 if (monmessages
[mon
.name
]) {
112 if (monmessages
[mon
.name
].worstSeverity
< mon
.health
) {
113 mon
.health
= monmessages
[mon
.name
].worstSeverity
;
115 Array
.prototype.push
.apply(mon
.messages
, monmessages
[mon
.name
].messages
);
120 if (mgrmessages
[mgr
.name
] === 'active') {
121 mgr
.title
= '<b>' + mgr
.title
+ '</b>';
122 mgr
.statuses
.push(gettext('Status') + ': <b>active</b>');
123 } else if (mgrmessages
[mgr
.name
] === 'standby') {
124 mgr
.statuses
.push(gettext('Status') + ': standby');
125 } else if (mgr
.health
> healthstates
.HEALTH_WARN
) {
126 mgr
.health
= healthstates
.HEALTH_WARN
;
132 if (mdsmessages
[mds
.name
]) {
133 mds
.title
= '<b>' + mds
.title
+ '</b>';
134 mds
.statuses
.push(gettext('Status') + ': <b>' + mdsmessages
[mds
.name
]+"</b>");
135 } else if (mds
.addr
!== Proxmox
.Utils
.unknownText
) {
136 mds
.statuses
.push(gettext('Status') + ': standby');
143 for (let type
of ['mon', 'mgr', 'mds']) {
144 var ids
= Object
.keys(metadata
[type
] || {});
147 for (let id
of ids
) {
148 const [name
, host
] = id
.split('@');
151 health
: healthstates
.HEALTH_OK
,
155 title
: metadata
[type
][id
].name
|| name
,
157 version
: PVE
.Utils
.parse_ceph_version(metadata
[type
][id
]),
158 service
: metadata
[type
][id
].service
,
159 addr
: metadata
[type
][id
].addr
|| metadata
[type
][id
].addrs
|| Proxmox
.Utils
.unknownText
,
163 gettext('Host') + ": " + host
,
164 gettext('Address') + ": " + result
.addr
,
168 result
= checks
[type
](result
);
171 if (result
.service
&& !result
.version
) {
172 result
.messages
.push(
173 PVE
.Utils
.get_ceph_icon_html('HEALTH_UNKNOWN', true) +
176 result
.health
= healthstates
.HEALTH_UNKNOWN
;
179 if (!result
.version
&& result
.addr
=== Proxmox
.Utils
.unknownText
) {
180 result
.health
= healthstates
.HEALTH_UNKNOWN
;
183 if (result
.version
) {
184 result
.statuses
.push(gettext('Version') + ": " + result
.version
);
186 if (PVE
.Utils
.compare_ceph_versions(result
.version
, maxversion
) !== 0) {
187 let host_version
= metadata
.node
[host
]?.version
?.parts
|| metadata
.version
?.[host
] || "";
188 if (PVE
.Utils
.compare_ceph_versions(host_version
, maxversion
) === 0) {
189 if (result
.health
> healthstates
.HEALTH_OLD
) {
190 result
.health
= healthstates
.HEALTH_OLD
;
192 result
.messages
.push(
193 PVE
.Utils
.get_ceph_icon_html('HEALTH_OLD', true) +
194 gettext('A newer version was installed but old version still running, please restart'),
197 if (result
.health
> healthstates
.HEALTH_UPGRADE
) {
198 result
.health
= healthstates
.HEALTH_UPGRADE
;
200 result
.messages
.push(
201 PVE
.Utils
.get_ceph_icon_html('HEALTH_UPGRADE', true) +
202 gettext('Other cluster members use a newer version of this service, please upgrade and restart'),
208 result
.statuses
.push(''); // empty line
209 result
.text
= result
.statuses
.concat(result
.messages
).join('<br>');
211 result
.health
= healthmap
[result
.health
];
213 me
[type
][id
] = result
;
217 me
.getComponent('mons').updateAll(Object
.values(me
.mon
));
218 me
.getComponent('mgrs').updateAll(Object
.values(me
.mgr
));
219 me
.getComponent('mdss').updateAll(Object
.values(me
.mds
));
223 Ext
.define('PVE.ceph.ServiceList', {
224 extend
: 'Ext.container.Container',
225 xtype
: 'pveCephServiceList',
228 'text-align': 'center',
233 'text-align': 'center',
243 tpl
: '<h3>{title}</h3>',
247 updateAll: function(list
) {
249 me
.suspendLayout
= true;
251 list
.sort((a
, b
) => a
.id
> b
.id
? 1 : a
.id
< b
.id
? -1 : 0);
255 let pendingRemoval
= {};
256 me
.ids
.forEach(id
=> { pendingRemoval
[id
] = true; }); // mark all as to-remove first here
258 for (let i
= 0; i
< list
.length
; i
++) {
259 let service
= me
.getComponent(list
[i
].id
);
261 // services and list are sorted, so just insert at i + 1 (first el. is the title)
262 service
= me
.insert(i
+ 1, {
263 xtype
: 'pveCephServiceWidget',
266 me
.ids
.push(list
[i
].id
);
268 delete pendingRemoval
[list
[i
].id
]; // drop exisiting from for-removal
270 service
.updateService(list
[i
].title
, list
[i
].text
, list
[i
].health
);
272 Object
.keys(pendingRemoval
).forEach(id
=> me
.remove(id
)); // GC
274 me
.suspendLayout
= false;
278 initComponent: function() {
281 me
.getComponent('title').update({
287 Ext
.define('PVE.ceph.ServiceWidget', {
288 extend
: 'Ext.Component',
289 alias
: 'widget.pveCephServiceWidget',
291 userCls
: 'monitor inline-block',
294 health
: 'HEALTH_ERR',
296 iconCls
: PVE
.Utils
.get_health_icon(),
301 '<i class="fa fa-fw {iconCls}"></i>',
304 updateService: function(title
, text
, health
) {
307 me
.update(Ext
.apply(me
.data
, {
311 iconCls
: PVE
.Utils
.get_health_icon(PVE
.Utils
.map_ceph_health
[health
]),
315 me
.tooltip
.setHtml(text
);
320 destroy: function() {
323 me
.tooltip
.destroy();
329 fn: function(events
, element
) {
330 let view
= this.component
;
334 if (!view
.tooltip
|| view
.data
.text
!== view
.tooltip
.html
) {
335 view
.tooltip
= Ext
.create('Ext.tip.ToolTip', {
339 renderTo
: Ext
.getBody(),
340 html
: view
.data
.text
,
348 fn: function(events
, element
) {
349 let view
= this.component
;
351 view
.tooltip
.destroy();