This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.1
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.1 by this push:
new 36cc49e Issue 50699 - Add Disk Monitor to CLI and UI
36cc49e is described below
commit 36cc49ef87ce56171d460d23c656b8be9e9f58be
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Mon Nov 11 11:52:52 2019 -0500
Issue 50699 - Add Disk Monitor to CLI and UI
Description: Add the disk monitoring to the CLI and UI
relates:
https://pagure.io/389-ds-base/issue/50699
Reviewed by: spichugi(Thanks!)
---
.../389-console/src/lib/monitor/monitorTables.jsx | 118 ++++++++++++++++++++-
.../389-console/src/lib/monitor/serverMonitor.jsx | 18 +++-
src/cockpit/389-console/src/monitor.jsx | 47 +++++++-
src/lib389/lib389/cli_conf/monitor.py | 39 ++++++-
src/lib389/lib389/utils.py | 13 +++
5 files changed, 229 insertions(+), 6 deletions(-)
diff --git a/src/cockpit/389-console/src/lib/monitor/monitorTables.jsx
b/src/cockpit/389-console/src/lib/monitor/monitorTables.jsx
index c401196..26db0ca 100644
--- a/src/cockpit/389-console/src/lib/monitor/monitorTables.jsx
+++ b/src/cockpit/389-console/src/lib/monitor/monitorTables.jsx
@@ -8,7 +8,7 @@ import {
tableCellFormatter,
noop
} from "patternfly-react";
-import { DSTable } from "../dsTable.jsx";
+import { DSTable, DSShortTable } from "../dsTable.jsx";
import PropTypes from "prop-types";
import "../../css/ds.css";
import { get_date_string } from "../tools.jsx";
@@ -1584,6 +1584,121 @@ class ConflictTable extends React.Component {
}
}
+class DiskTable extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ rowKey: "mount",
+ columns: [
+ {
+ property: "mount",
+ header: {
+ label: "Disk Partition",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "size",
+ header: {
+ label: "Disk Size",
+ props: {
+ index: 1,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 1
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "used",
+ header: {
+ label: "Used Space",
+ props: {
+ index: 2,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 2
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "avail",
+ header: {
+ label: "Available Space",
+ props: {
+ index: 3,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 3
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+
+ ]
+ };
+ this.getColumns = this.getColumns.bind(this);
+ }
+
+ getColumns() {
+ return this.state.columns;
+ }
+
+ render() {
+ return (
+ <div className="ds-margin-top-xlg">
+ <DSShortTable
+ getColumns={this.getColumns}
+ rowKey={this.state.rowKey}
+ rows={this.props.disks}
+ disableLoadingSpinner
+ />
+ </div>
+ );
+ }
+}
+
// Proptypes and defaults
LagReportTable.propTypes = {
@@ -1681,4 +1796,5 @@ export {
AbortCleanALLRUVTable,
ConflictTable,
GlueTable,
+ DiskTable,
};
diff --git a/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
index e330f82..b150907 100644
--- a/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
+++ b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
@@ -3,9 +3,11 @@ import PropTypes from "prop-types";
import "../../css/ds.css";
import { get_date_string, get_date_diff } from "../tools.jsx";
import {
- ConnectionTable
+ ConnectionTable,
+ DiskTable,
} from "./monitorTables.jsx";
import {
+ Button,
Nav,
NavItem,
TabContent,
@@ -66,6 +68,9 @@ export class ServerMonitor extends React.Component {
<NavItem eventKey={2}>
<div dangerouslySetInnerHTML={{__html: 'Connection
Table'}} />
</NavItem>
+ <NavItem eventKey={3}>
+ <div dangerouslySetInnerHTML={{__html: 'Disk
Space'}} />
+ </NavItem>
</Nav>
<TabContent>
@@ -191,6 +196,17 @@ export class ServerMonitor extends React.Component {
<TabPane eventKey={2}>
<ConnectionTable conns={this.props.data.connection}
/>
</TabPane>
+ <TabPane eventKey={3}>
+ <DiskTable
+ disks={this.props.disks}
+ />
+ <Button
+ className="ds-margin-top"
+ onClick={this.props.reloadDisks}
+ >
+ Refresh
+ </Button>
+ </TabPane>
</TabContent>
</div>
</TabContainer>
diff --git a/src/cockpit/389-console/src/monitor.jsx
b/src/cockpit/389-console/src/monitor.jsx
index d9d7807..6798dda 100644
--- a/src/cockpit/389-console/src/monitor.jsx
+++ b/src/cockpit/389-console/src/monitor.jsx
@@ -39,6 +39,7 @@ export class Monitor extends React.Component {
snmpData: {},
ldbmData: {},
serverData: {},
+ disks: [],
loadingMsg: "",
notifications: [],
disableTree: false,
@@ -124,6 +125,8 @@ export class Monitor extends React.Component {
this.loadMonitorServer = this.loadMonitorServer.bind(this);
this.reloadServer = this.reloadServer.bind(this);
this.loadMonitorChaining = this.loadMonitorChaining.bind(this);
+ this.loadDiskSpace = this.loadDiskSpace.bind(this);
+ this.reloadDisks = this.reloadDisks.bind(this);
// Replication
this.loadMonitorReplication = this.loadMonitorReplication.bind(this);
this.loadCleanTasks = this.loadCleanTasks.bind(this);
@@ -457,7 +460,7 @@ export class Monitor extends React.Component {
replicatedSuffixes: config.items,
replSuffix: replSuffix,
});
- }, this.loadMonitorLDBM());
+ }, this.loadDiskSpace());
}
loadMonitorLDBM() {
@@ -528,7 +531,7 @@ export class Monitor extends React.Component {
this.setState({
serverLoading: false,
serverData: config.attrs
- });
+ }, this.reloadDisks());
});
}
@@ -548,6 +551,44 @@ export class Monitor extends React.Component {
});
}
+ loadDiskSpace() {
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-"
+ this.props.serverId + ".socket",
+ "monitor", "disk"
+ ];
+ log_cmd("loadDiskSpace", "Load disk space info", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let disks = JSON.parse(content);
+ for (let disk of disks.items) {
+ disk.used = disk.used + " (" + disk.percent +
"%)";
+ }
+ this.setState({
+ disks: disks.items
+ });
+ }, this.loadMonitorLDBM());
+ }
+
+ reloadDisks () {
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-"
+ this.props.serverId + ".socket",
+ "monitor", "disk"
+ ];
+ log_cmd("reloadDisks", "Reload disk stats", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let disks = JSON.parse(content);
+ for (let disk of disks.items) {
+ disk.used = disk.used + " (" + disk.percent +
"%)";
+ }
+ this.setState({
+ disks: disks.items,
+ });
+ });
+ }
+
reloadSNMP() {
this.setState({
snmpLoading: true
@@ -1053,6 +1094,8 @@ export class Monitor extends React.Component {
data={this.state.serverData}
reload={this.reloadServer}
serverId={this.props.serverId}
+ disks={this.state.disks}
+ reloadDisks={this.reloadDisks}
enableTree={this.enableTree}
/>;
}
diff --git a/src/lib389/lib389/cli_conf/monitor.py
b/src/lib389/lib389/cli_conf/monitor.py
index 87eb75f..ff3712e 100644
--- a/src/lib389/lib389/cli_conf/monitor.py
+++ b/src/lib389/lib389/cli_conf/monitor.py
@@ -7,9 +7,11 @@
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
-from lib389.monitor import (Monitor, MonitorLDBM, MonitorSNMP)
+import json
+from lib389.monitor import (Monitor, MonitorLDBM, MonitorSNMP, MonitorDiskSpace)
from lib389.chaining import (ChainingLinks)
from lib389.backend import Backends
+from lib389.utils import convert_bytes
def _format_status(log, mtype, json=False):
@@ -63,9 +65,39 @@ def chaining_monitor(inst, basedn, log, args):
for link in links.list():
link_monitor = link.get_monitor()
_format_status(log, link_monitor, args.json)
- # Inejct a new line for now ... see
https://pagure.io/389-ds-base/issue/50189
+ # Inject a new line for now ... see
https://pagure.io/389-ds-base/issue/50189
log.info("")
+def disk_monitor(inst, basedn, log, args):
+ disk_space_mon = MonitorDiskSpace(inst)
+ disks = disk_space_mon.get_disks()
+ disk_list = []
+ for disk in disks:
+ # partition="/" size="52576092160"
used="25305038848" available="27271053312" use%="48"
+ parts = disk.split()
+ mount = parts[0].split('=')[1].strip('"')
+ disk_size =
convert_bytes(parts[1].split('=')[1].strip('"'))
+ used = convert_bytes(parts[2].split('=')[1].strip('"'))
+ avail = convert_bytes(parts[3].split('=')[1].strip('"'))
+ percent = parts[4].split('=')[1].strip('"')
+ if args.json:
+ disk_list.append({
+ 'mount': mount,
+ 'size': disk_size,
+ 'used': used,
+ 'avail': avail,
+ 'percent': percent
+ })
+ else:
+ log.info("Partition: " + mount)
+ log.info("Size: " + disk_size)
+ log.info("Used Space: " + used)
+ log.info("Available Space: " + avail)
+ log.info("Percentage Used: " + percent + "%\n")
+
+ if args.json:
+ log.info(json.dumps({"type": "list", "items":
disk_list}))
+
def create_parser(subparsers):
monitor_parser = subparsers.add_parser('monitor', help="Monitor the
state of the instance")
@@ -87,3 +119,6 @@ def create_parser(subparsers):
chaining_parser = subcommands.add_parser('chaining', help="Monitor
database chaining statistics")
chaining_parser.add_argument('backend', nargs='?',
help="Optional name of the chaining backend to monitor")
chaining_parser.set_defaults(func=chaining_monitor)
+
+ disk_parser = subcommands.add_parser('disk', help="Disk space
statistics. All values are in bytes")
+ disk_parser.set_defaults(func=disk_monitor)
diff --git a/src/lib389/lib389/utils.py b/src/lib389/lib389/utils.py
index c271d86..a0b063a 100644
--- a/src/lib389/lib389/utils.py
+++ b/src/lib389/lib389/utils.py
@@ -39,6 +39,8 @@ import six
import shlex
import operator
import subprocess
+import math
+from packaging.version import LegacyVersion
from socket import getfqdn
from ldapurl import LDAPUrl
from contextlib import closing
@@ -1301,3 +1303,14 @@ def display_log_value(attr, value, hide_sensitive=True):
def display_log_data(data, hide_sensitive=True):
# Take a dict and mask all the sensitive data
return {a: display_log_value(a, v, hide_sensitive) for a, v in data.items()}
+
+
+def convert_bytes(bytes):
+ bytes = int(bytes)
+ if bytes == 0:
+ return "0 B"
+ size_name = ["B", "KB", "MB", "GB",
"TB", "PB"]
+ i = int(math.floor(math.log(bytes, 1024)))
+ pow = math.pow(1024, i)
+ siz = round(bytes / pow, 2)
+ return "{} {}".format(siz, size_name[i])
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.