[pve-devel] [PATCH manager 14/20] gui: ceph: add ServiceList component and use it
Dominik Csapak
d.csapak at proxmox.com
Tue Jun 4 14:47:53 CEST 2019
this is an abstraction for listing Ceph Services with a few improvements:
* start/stop/restart buttons for all services (incl. icons)
* a syslog button to view the syslog of that service
* correct reloading behaviour when creating/destroying
Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
www/manager6/Makefile | 1 +
www/manager6/ceph/Monitor.js | 252 ++++--------------------------
www/manager6/ceph/ServiceList.js | 324 +++++++++++++++++++++++++++++++++++++++
www/manager6/node/Config.js | 2 +-
4 files changed, 358 insertions(+), 221 deletions(-)
create mode 100644 www/manager6/ceph/ServiceList.js
diff --git a/www/manager6/Makefile b/www/manager6/Makefile
index 2f25a83f..c8673533 100644
--- a/www/manager6/Makefile
+++ b/www/manager6/Makefile
@@ -96,6 +96,7 @@ JSSRC= \
panel/IPSet.js \
panel/ConfigPanel.js \
grid/BackupView.js \
+ ceph/ServiceList.js \
ceph/FS.js \
ceph/Pool.js \
ceph/OSD.js \
diff --git a/www/manager6/ceph/Monitor.js b/www/manager6/ceph/Monitor.js
index 638fa9f1..eb35e91c 100644
--- a/www/manager6/ceph/Monitor.js
+++ b/www/manager6/ceph/Monitor.js
@@ -1,234 +1,46 @@
-Ext.define('PVE.CephCreateMon', {
- extend: 'Proxmox.window.Edit',
- alias: ['widget.pveCephCreateMon'],
+Ext.define('PVE.node.CephMonMgrList', {
+ extend: 'Ext.container.Container',
+ xtype: 'pveNodeCephMonMgr',
- subject: 'Ceph Monitor/Manager',
- onlineHelp: 'pve_ceph_monitors',
-
- showProgress: true,
-
- setNode: function(nodename) {
- var me = this;
-
- me.nodename = nodename;
- me.url = "/nodes/" + nodename + "/ceph/mon";
- },
-
- initComponent : function() {
-
- var me = this;
-
- if (!me.nodename) {
- throw "no node name specified";
- }
-
- me.setNode(me.nodename);
-
- me.isCreate = true;
-
- Ext.applyIf(me, {
- method: 'POST',
- items: [
- {
- xtype: 'pveNodeSelector',
- submitValue: false,
- fieldLabel: gettext('Host'),
- selectCurNode: true,
- allowBlank: false,
- listeners: {
- change: function(f, value) {
- me.setNode(value);
- }
- }
- }
- ]
- });
-
- me.callParent();
- }
-});
-
-Ext.define('PVE.node.CephMonList', {
- extend: 'Ext.grid.GridPanel',
- alias: ['widget.pveNodeCephMonList'],
+ mixins: ['Proxmox.Mixin.CBind' ],
onlineHelp: 'chapter_pveceph',
- stateful: true,
- stateId: 'grid-ceph-monitor',
-
- initComponent: function() {
- var me = this;
-
- var nodename = me.pveSelNode.data.node;
- if (!nodename) {
- throw "no node name specified";
- }
-
- var sm = Ext.create('Ext.selection.RowModel', {});
-
- var rstore = Ext.create('Proxmox.data.UpdateStore', {
- interval: 3000,
- storeid: 'ceph-mon-list' + nodename,
- model: 'ceph-mon-list',
- proxy: {
- type: 'proxmox',
- url: "/api2/json/nodes/" + nodename + "/ceph/mon"
- }
- });
-
- var store = Ext.create('Proxmox.data.DiffStore', {
- rstore: rstore,
- sorters: [{ property: 'name'}]
- });
-
-
- var service_cmd = function(cmd) {
- var rec = sm.getSelection()[0];
- if (!rec.data.host) {
- Ext.Msg.alert(gettext('Error'), "entry has no host");
- return;
- }
- Proxmox.Utils.API2Request({
- url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
- method: 'POST',
- params: { service: "mon." + rec.data.name },
- success: function(response, options) {
- var upid = response.result.data;
- var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
- win.show();
- },
- failure: function(response, opts) {
- Ext.Msg.alert(gettext('Error'), response.htmlStatus);
- }
- });
- };
-
- var start_btn = new Proxmox.button.Button({
- text: gettext('Start'),
- selModel: sm,
- disabled: true,
- handler: function(){
- service_cmd("start");
- }
- });
-
- var stop_btn = new Proxmox.button.Button({
- text: gettext('Stop'),
- selModel: sm,
- disabled: true,
- handler: function(){
- service_cmd("stop");
- }
- });
-
- var restart_btn = new Proxmox.button.Button({
- text: gettext('Restart'),
- selModel: sm,
- disabled: true,
- handler: function(){
- service_cmd("restart");
- }
- });
-
- var create_btn = new Ext.Button({
- text: gettext('Create'),
- handler: function(){
- var win = Ext.create('PVE.CephCreateMon', {
- nodename: nodename
- });
- win.show();
- }
- });
-
- var remove_btn = new Proxmox.button.Button({
- text: gettext('Remove'),
- selModel: sm,
- disabled: true,
- handler: function() {
- var rec = sm.getSelection()[0];
-
- if (!rec.data.host) {
- Ext.Msg.alert(gettext('Error'), "entry has no host");
- return;
- }
+ defaults: {
+ border: false,
+ onlineHelp: 'chapter_pveceph',
+ flex: 1
+ },
- Proxmox.Utils.API2Request({
- url: "/nodes/" + rec.data.host + "/ceph/mon/" +
- rec.data.name,
- method: 'DELETE',
- success: function(response, options) {
- var upid = response.result.data;
- var win = Ext.create('Proxmox.window.TaskProgress', { upid: upid });
- win.show();
- },
- failure: function(response, opts) {
- Ext.Msg.alert(gettext('Error'), response.htmlStatus);
- }
- });
- }
- });
+ layout: {
+ type: 'vbox',
+ align: 'stretch'
+ },
- Ext.apply(me, {
- store: store,
- selModel: sm,
- tbar: [ start_btn, stop_btn, restart_btn, '-', create_btn, remove_btn ],
- columns: [
- {
- header: gettext('Name'),
- width: 100,
- sortable: true,
- renderer: function(v) { return "mon." + v; },
- dataIndex: 'name'
- },
- {
- header: gettext('Host'),
- width: 100,
- sortable: true,
- renderer: function(v) {
- return v || 'unknown';
- },
- dataIndex: 'host'
- },
+ items: [
+ {
+ xtype: 'pveNodeCephServiceList',
+ cbind: { pveSelNode: '{pveSelNode}' },
+ type: 'mon',
+ additionalColumns: [
{
header: gettext('Quorum'),
width: 70,
- sortable: false,
+ sortable: true,
renderer: Proxmox.Utils.format_boolean,
dataIndex: 'quorum'
- },
- {
- header: gettext('Address'),
- flex: 1,
- sortable: true,
- dataIndex: 'addr'
}
],
- listeners: {
- activate: rstore.startUpdate,
- destroy: rstore.stopUpdate
- }
- });
-
- var regex = new RegExp("not (installed|initialized)", "i");
- PVE.Utils.handleStoreErrorOrMask(me, rstore, regex, function(me, error){
- me.store.rstore.stopUpdate();
- PVE.Utils.showCephInstallOrMask(me, error.statusText, nodename,
- function(win){
- me.mon(win, 'cephInstallWindowClosed', function(){
- me.store.rstore.startUpdate();
- });
- }
- );
- });
-
- me.callParent();
- }
-}, function() {
-
- Ext.define('ceph-mon-list', {
- extend: 'Ext.data.Model',
- fields: [ 'addr', 'name', 'rank', 'host', 'quorum' ],
- idProperty: 'name'
- });
+ stateId: 'grid-ceph-monitor',
+ showCephInstallMask: true,
+ title: gettext('Monitor')
+ },
+ {
+ xtype: 'pveNodeCephServiceList',
+ type: 'mgr',
+ stateId: 'grid-ceph-manager',
+ cbind: { pveSelNode: '{pveSelNode}' },
+ title: gettext('Manager')
+ }
+ ]
});
diff --git a/www/manager6/ceph/ServiceList.js b/www/manager6/ceph/ServiceList.js
new file mode 100644
index 00000000..16b41fcc
--- /dev/null
+++ b/www/manager6/ceph/ServiceList.js
@@ -0,0 +1,324 @@
+Ext.define('PVE.CephCreateService', {
+ extend: 'Proxmox.window.Edit',
+ xtype: 'pveCephCreateService',
+
+ showProgress: true,
+
+ setNode: function(nodename) {
+ var me = this;
+
+ me.nodename = nodename;
+ me.url = "/nodes/" + nodename + "/ceph/" + me.type;
+ },
+
+ method: 'POST',
+ isCreate: true,
+
+ items: [
+ {
+ xtype: 'pveNodeSelector',
+ submitValue: false,
+ fieldLabel: gettext('Host'),
+ selectCurNode: true,
+ allowBlank: false,
+ listeners: {
+ change: function(f, value) {
+ var me = this.up('pveCephCreateService');
+ me.setNode(value);
+ }
+ }
+ }
+ ],
+
+ initComponent : function() {
+ var me = this;
+
+ if (!me.nodename) {
+ throw "no node name specified";
+ }
+
+ if (!me.type) {
+ throw "no type specified";
+ }
+
+ me.setNode(me.nodename);
+
+ me.callParent();
+ }
+});
+
+Ext.define('PVE.node.CephServiceList', {
+ extend: 'Ext.grid.GridPanel',
+ xtype: 'pveNodeCephServiceList',
+
+ onlineHelp: 'chapter_pveceph',
+ emptyText: Ext.String.format(gettext('No {0} configured.'), 'MDS'),
+
+ stateful: true,
+
+ // will be called when the store loads
+ storeLoadCallback: Ext.emptyFn,
+
+ // if set to true, does shows the ceph install mask if needed
+ showCephInstallMask: false,
+
+ controller: {
+ xclass: 'Ext.app.ViewController',
+
+ init: function(view) {
+ if (view.pveSelNode) {
+ view.nodename = view.pveSelNode.data.node;
+ }
+ if (!view.nodename) {
+ throw "no node name specified";
+ }
+
+ if (!view.type) {
+ throw "no type specified";
+ }
+
+ view.rstore = Ext.create('Proxmox.data.UpdateStore', {
+ autoLoad: true,
+ autoStart: true,
+ interval: 3000,
+ storeid: 'ceph-' + view.type + '-list' + view.nodename,
+ model: 'ceph-service-list',
+ proxy: {
+ type: 'proxmox',
+ url: "/api2/json/nodes/" + view.nodename + "/ceph/" + view.type
+ }
+ });
+
+ view.setStore(Ext.create('Proxmox.data.DiffStore', {
+ rstore: view.rstore,
+ sorters: [{ property: 'name' }]
+ }));
+
+ if (view.storeLoadCallback) {
+ view.rstore.on('load', view.storeLoadCallback, this);
+ }
+ view.on('destroy', view.rstore.stopUpdate);
+
+ if (view.showCephInstallMask) {
+ var regex = new RegExp("not (installed|initialized)", "i");
+ PVE.Utils.handleStoreErrorOrMask(view, view.rstore, regex, function(me, error) {
+ view.rstore.stopUpdate();
+ PVE.Utils.showCephInstallOrMask(view.ownerCt, error.statusText, view.nodename,
+ function(win){
+ me.mon(win, 'cephInstallWindowClosed', function(){
+ view.rstore.startUpdate();
+ });
+ }
+ );
+ });
+ }
+ },
+
+ service_cmd: function(rec, cmd) {
+ var view = this.getView();
+ if (!rec.data.host) {
+ Ext.Msg.alert(gettext('Error'), "entry has no host");
+ return;
+ }
+ Proxmox.Utils.API2Request({
+ url: "/nodes/" + rec.data.host + "/ceph/" + cmd,
+ method: 'POST',
+ params: { service: view.type + '.' + rec.data.name },
+ success: function(response, options) {
+ var upid = response.result.data;
+ var win = Ext.create('Proxmox.window.TaskProgress', {
+ upid: upid,
+ taskDone: function() {
+ view.rstore.load();
+ }
+ });
+ win.show();
+ },
+ failure: function(response, opts) {
+ Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+ }
+ });
+ },
+ onChangeService: function(btn) {
+ var me = this;
+ var view = this.getView();
+ var cmd = btn.action;
+ var rec = view.getSelection()[0];
+ me.service_cmd(rec, cmd);
+ },
+
+ showSyslog: function() {
+ var view = this.getView();
+ var rec = view.getSelection()[0];
+ var servicename = 'ceph-' + view.type + '@' + rec.data.name;
+ var url = "/api2/extjs/nodes/" + rec.data.host + "/syslog?service=" + encodeURIComponent(servicename);
+ var win = Ext.create('Ext.window.Window', {
+ title: gettext('Syslog') + ': ' + servicename,
+ modal: true,
+ items: [{
+ xtype: 'proxmoxLogView',
+ width: 800,
+ height: 400,
+ url: url,
+ log_select_timespan: 1
+ }]
+ });
+ win.show();
+ },
+
+ onCreate: function() {
+ var view = this.getView();
+ var win = Ext.create('PVE.CephCreateService', {
+ autoShow: true,
+ nodename: view.nodename,
+ subject: view.getTitle(),
+ type: view.type,
+ taskDone: function() {
+ view.rstore.load();
+ }
+ });
+ }
+ },
+
+ tbar: [
+ {
+ xtype: 'proxmoxButton',
+ text: gettext('Start'),
+ iconCls: 'fa fa-play',
+ action: 'start',
+ disabled: true,
+ enableFn: function(rec) {
+ return rec.data.state === 'stopped' ||
+ rec.data.state === 'unknown';
+ },
+ handler: 'onChangeService'
+ },
+ {
+ xtype: 'proxmoxButton',
+ text: gettext('Stop'),
+ iconCls: 'fa fa-stop',
+ action: 'stop',
+ enableFn: function(rec) {
+ return rec.data.state !== 'stopped';
+ },
+ disabled: true,
+ handler: 'onChangeService'
+ },
+ {
+ xtype: 'proxmoxButton',
+ text: gettext('Restart'),
+ iconCls: 'fa fa-refresh',
+ action: 'restart',
+ disabled: true,
+ enableFn: function(rec) {
+ return rec.data.state !== 'stopped';
+ },
+ handler: 'onChangeService'
+ },
+ '-',
+ {
+ text: gettext('Create'),
+ reference: 'createButton',
+ handler: 'onCreate'
+ },
+ {
+ text: gettext('Destroy'),
+ xtype: 'proxmoxStdRemoveButton',
+ getUrl: function(rec) {
+ var view = this.up('grid');
+ if (!rec.data.host) {
+ Ext.Msg.alert(gettext('Error'), "entry has no host");
+ return;
+ }
+ return "/nodes/" + rec.data.host + "/ceph/" + view.type + "/" + rec.data.name;
+ },
+ callback: function(options, success, response) {
+ var view = this.up('grid');
+ if (!success) {
+ Ext.Msg.alert(gettext('Error'), response.htmlStatus);
+ return;
+ }
+ var upid = response.result.data;
+ var win = Ext.create('Proxmox.window.TaskProgress', {
+ upid: upid,
+ taskDone: function() {
+ view.rstore.load();
+ }
+ });
+ win.show();
+ }
+ },
+ '-',
+ {
+ xtype: 'proxmoxButton',
+ text: gettext('Syslog'),
+ disabled: true,
+ handler: 'showSyslog'
+ }
+ ],
+
+ columns: [
+ {
+ header: gettext('Name'),
+ width: 100,
+ sortable: true,
+ renderer: function(v) {
+ return this.type + '.' + v;
+ },
+ dataIndex: 'name'
+ },
+ {
+ header: gettext('Host'),
+ width: 100,
+ sortable: true,
+ renderer: function(v) {
+ return v || Proxmox.Utils.unknownText;
+ },
+ dataIndex: 'host'
+ },
+ {
+ header: gettext('Status'),
+ width: 70,
+ sortable: false,
+ dataIndex: 'state'
+ },
+ {
+ header: gettext('Address'),
+ flex: 1,
+ sortable: true,
+ renderer: function(v) {
+ return v || Proxmox.Utils.unknownText;
+ },
+ dataIndex: 'addr'
+ },
+ {
+ header: gettext('Version'),
+ flex: 1,
+ sortable: true,
+ dataIndex: 'version'
+ }
+ ],
+
+ initComponent: function() {
+ var me = this;
+
+ if (me.additionalColumns) {
+ me.columns = me.columns.concat(me.additionalColumns);
+ }
+
+ me.callParent();
+ }
+
+}, function() {
+
+ Ext.define('ceph-service-list', {
+ extend: 'Ext.data.Model',
+ fields: [ 'addr', 'name', 'rank', 'host', 'quorum', 'state',
+ 'ceph_version', 'ceph_version_short',
+ { type: 'string', name: 'version', calculate: function(data) {
+ return PVE.Utils.parse_ceph_version(data);
+ } }
+ ],
+ idProperty: 'name'
+ });
+});
diff --git a/www/manager6/node/Config.js b/www/manager6/node/Config.js
index 700ca611..054ced64 100644
--- a/www/manager6/node/Config.js
+++ b/www/manager6/node/Config.js
@@ -326,7 +326,7 @@ Ext.define('PVE.node.Config', {
itemId: 'ceph-config'
},
{
- xtype: 'pveNodeCephMonList',
+ xtype: 'pveNodeCephMonMgr',
title: gettext('Monitor'),
iconCls: 'fa fa-tv',
groups: ['ceph'],
--
2.11.0
More information about the pve-devel
mailing list