[389-ds-base] branch 389-ds-base-1.4.1 updated: Issue 50499 - Fix npm audit issues
by pagure@pagure.io
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 a6c26fb Issue 50499 - Fix npm audit issues
a6c26fb is described below
commit a6c26fb8c15bc02526789b3b0760ec6a1f8ac4ed
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Wed Nov 13 16:18:53 2019 -0500
Issue 50499 - Fix npm audit issues
Description: Updated npm handlebars package to 4.4.5
relates: https://pagure.io/389-ds-base/issue/50499
---
src/cockpit/389-console/package-lock.json | 39 +++++++++----------------------
1 file changed, 11 insertions(+), 28 deletions(-)
diff --git a/src/cockpit/389-console/package-lock.json b/src/cockpit/389-console/package-lock.json
index d43c297..7207e92 100644
--- a/src/cockpit/389-console/package-lock.json
+++ b/src/cockpit/389-console/package-lock.json
@@ -6906,9 +6906,9 @@
"optional": true
},
"js-base64": {
- "version": "2.4.9",
- "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.9.tgz",
- "integrity": "sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ=="
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
+ "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw=="
},
"js-levenshtein": {
"version": "1.1.4",
@@ -7183,26 +7183,11 @@
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
"integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw=="
},
- "lodash.assign": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
- "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
- },
- "lodash.clonedeep": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
- "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
- },
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
},
- "lodash.mergewith": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
- "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
- },
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -7543,9 +7528,9 @@
"dev": true
},
"nan": {
- "version": "2.11.1",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.11.1.tgz",
- "integrity": "sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA=="
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
},
"nanomatch": {
"version": "1.2.13",
@@ -7667,9 +7652,9 @@
}
},
"node-sass": {
- "version": "4.11.0",
- "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz",
- "integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==",
+ "version": "4.12.0",
+ "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz",
+ "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==",
"requires": {
"async-foreach": "^0.1.3",
"chalk": "^1.1.1",
@@ -7678,12 +7663,10 @@
"get-stdin": "^4.0.1",
"glob": "^7.0.3",
"in-publish": "^2.0.0",
- "lodash.assign": "^4.2.0",
- "lodash.clonedeep": "^4.3.2",
- "lodash.mergewith": "^4.6.0",
+ "lodash": "^4.17.11",
"meow": "^3.7.0",
"mkdirp": "^0.5.1",
- "nan": "^2.10.0",
+ "nan": "^2.13.2",
"node-gyp": "^3.8.0",
"npmlog": "^4.0.0",
"request": "^2.88.0",
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.4.0 updated: Issue 50699 - Add Disk Monitor to CLI and UI
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 9ffa0df Issue 50699 - Add Disk Monitor to CLI and UI
9ffa0df is described below
commit 9ffa0df96d26504aa209f317fe48269a4f41f7f3
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.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.4.1 updated: Issue 50699 - Add Disk Monitor to CLI and UI
by pagure@pagure.io
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.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.3.10 updated: Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.3.10
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.10 by this push:
new b6ba778 Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
b6ba778 is described below
commit b6ba77876ca744ef3695d36f598314c8aa05ccec
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Wed Nov 13 12:34:54 2019 -0500
Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
Bug Description: If there is an ACI that allows "search" access to an attribute,
the deref plugin access control checks sees this is a "read"
privilege and returns the attribute's value.
Fix description: For deref plugin we are only concerned with "read" access, not
"search" access. Removed the SLAPI_ACL_SEARCH right flag when
checking access for an attribute.
relates: https://pagure.io/389-ds-base/issue/50716
Reviewed by: lkrispen & tbordaz(Thanks!)
---
ldap/servers/plugins/deref/deref.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ldap/servers/plugins/deref/deref.c b/ldap/servers/plugins/deref/deref.c
index cb5ebb8..ec1884b 100644
--- a/ldap/servers/plugins/deref/deref.c
+++ b/ldap/servers/plugins/deref/deref.c
@@ -573,7 +573,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
Slapi_Entry **entries = NULL;
int rc;
- /* If the access check on the attributes is done without retrieveing the entry
+ /* If the access check on the attributes is done without retrieving the entry
* it cannot handle acis which need teh entry, eg to apply a targetfilter rule
* So the determination of attrs which can be dereferenced is delayed
*/
@@ -596,7 +596,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
int ii;
int needattrvals = 1; /* need attrvals sequence? */
if (deref_check_access(pb, entries[0], derefdn, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_do_deref_attr - The client does not have permission to read the requested "
"attributes in entry %s\n",
@@ -714,7 +714,7 @@ deref_pre_entry(Slapi_PBlock *pb)
attrs[1] = NULL;
if (deref_check_access(pb, ent, NULL, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_pre_entry - The client does not have permission to read attribute %s in entry %s\n",
spec->derefattr, slapi_entry_get_dn_const(ent));
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.4.0 updated: Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new fca2934 Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
fca2934 is described below
commit fca2934270fcac49691956140f516b32900de027
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Wed Nov 13 12:34:54 2019 -0500
Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
Bug Description: If there is an ACI that allows "search" access to an attribute,
the deref plugin access control checks sees this is a "read"
privilege and returns the attribute's value.
Fix description: For deref plugin we are only concerned with "read" access, not
"search" access. Removed the SLAPI_ACL_SEARCH right flag when
checking access for an attribute.
relates: https://pagure.io/389-ds-base/issue/50716
Reviewed by: lkrispen & tbordaz(Thanks!)
---
ldap/servers/plugins/deref/deref.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ldap/servers/plugins/deref/deref.c b/ldap/servers/plugins/deref/deref.c
index cb5ebb8..ec1884b 100644
--- a/ldap/servers/plugins/deref/deref.c
+++ b/ldap/servers/plugins/deref/deref.c
@@ -573,7 +573,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
Slapi_Entry **entries = NULL;
int rc;
- /* If the access check on the attributes is done without retrieveing the entry
+ /* If the access check on the attributes is done without retrieving the entry
* it cannot handle acis which need teh entry, eg to apply a targetfilter rule
* So the determination of attrs which can be dereferenced is delayed
*/
@@ -596,7 +596,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
int ii;
int needattrvals = 1; /* need attrvals sequence? */
if (deref_check_access(pb, entries[0], derefdn, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_do_deref_attr - The client does not have permission to read the requested "
"attributes in entry %s\n",
@@ -714,7 +714,7 @@ deref_pre_entry(Slapi_PBlock *pb)
attrs[1] = NULL;
if (deref_check_access(pb, ent, NULL, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_pre_entry - The client does not have permission to read attribute %s in entry %s\n",
spec->derefattr, slapi_entry_get_dn_const(ent));
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.4.1 updated: Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
by pagure@pagure.io
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 86776bb Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
86776bb is described below
commit 86776bb22c175a8e718e98309ad67d2a76f30e60
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Wed Nov 13 12:34:54 2019 -0500
Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
Bug Description: If there is an ACI that allows "search" access to an attribute,
the deref plugin access control checks sees this is a "read"
privilege and returns the attribute's value.
Fix description: For deref plugin we are only concerned with "read" access, not
"search" access. Removed the SLAPI_ACL_SEARCH right flag when
checking access for an attribute.
relates: https://pagure.io/389-ds-base/issue/50716
Reviewed by: lkrispen & tbordaz(Thanks!)
---
ldap/servers/plugins/deref/deref.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ldap/servers/plugins/deref/deref.c b/ldap/servers/plugins/deref/deref.c
index cb5ebb8..ec1884b 100644
--- a/ldap/servers/plugins/deref/deref.c
+++ b/ldap/servers/plugins/deref/deref.c
@@ -573,7 +573,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
Slapi_Entry **entries = NULL;
int rc;
- /* If the access check on the attributes is done without retrieveing the entry
+ /* If the access check on the attributes is done without retrieving the entry
* it cannot handle acis which need teh entry, eg to apply a targetfilter rule
* So the determination of attrs which can be dereferenced is delayed
*/
@@ -596,7 +596,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
int ii;
int needattrvals = 1; /* need attrvals sequence? */
if (deref_check_access(pb, entries[0], derefdn, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_do_deref_attr - The client does not have permission to read the requested "
"attributes in entry %s\n",
@@ -714,7 +714,7 @@ deref_pre_entry(Slapi_PBlock *pb)
attrs[1] = NULL;
if (deref_check_access(pb, ent, NULL, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_pre_entry - The client does not have permission to read attribute %s in entry %s\n",
spec->derefattr, slapi_entry_get_dn_const(ent));
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months
[389-ds-base] branch master updated: Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch master
in repository 389-ds-base.
The following commit(s) were added to refs/heads/master by this push:
new ddbe3c8 Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
ddbe3c8 is described below
commit ddbe3c8fef93364581c9b189c49e125856d49505
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Wed Nov 13 12:34:54 2019 -0500
Issue 50716 - CVE-2019-14824 (BZ#1748199) - deref plugin displays restricted attributes
Bug Description: If there is an ACI that allows "search" access to an attribute,
the deref plugin access control checks sees this is a "read"
privilege and returns the attribute's value.
Fix description: For deref plugin we are only concerned with "read" access, not
"search" access. Removed the SLAPI_ACL_SEARCH right flag when
checking access for an attribute.
relates: https://pagure.io/389-ds-base/issue/50716
Reviewed by: lkrispen & tbordaz(Thanks!)
---
ldap/servers/plugins/deref/deref.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/ldap/servers/plugins/deref/deref.c b/ldap/servers/plugins/deref/deref.c
index cb5ebb8..ec1884b 100644
--- a/ldap/servers/plugins/deref/deref.c
+++ b/ldap/servers/plugins/deref/deref.c
@@ -573,7 +573,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
Slapi_Entry **entries = NULL;
int rc;
- /* If the access check on the attributes is done without retrieveing the entry
+ /* If the access check on the attributes is done without retrieving the entry
* it cannot handle acis which need teh entry, eg to apply a targetfilter rule
* So the determination of attrs which can be dereferenced is delayed
*/
@@ -596,7 +596,7 @@ deref_do_deref_attr(Slapi_PBlock *pb, BerElement *ctrlber, const char *derefdn,
int ii;
int needattrvals = 1; /* need attrvals sequence? */
if (deref_check_access(pb, entries[0], derefdn, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_do_deref_attr - The client does not have permission to read the requested "
"attributes in entry %s\n",
@@ -714,7 +714,7 @@ deref_pre_entry(Slapi_PBlock *pb)
attrs[1] = NULL;
if (deref_check_access(pb, ent, NULL, attrs, &retattrs,
- (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))) {
+ SLAPI_ACL_READ)) {
slapi_log_err(SLAPI_LOG_PLUGIN, DEREF_PLUGIN_SUBSYSTEM,
"deref_pre_entry - The client does not have permission to read attribute %s in entry %s\n",
spec->derefattr, slapi_entry_get_dn_const(ent));
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.4.0 updated: Issue 50696 - Fix various UI bugs
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 959057c Issue 50696 - Fix various UI bugs
959057c is described below
commit 959057ccacfc99779e1ba25d4c28321278d30e6c
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Thu Nov 7 16:21:21 2019 -0500
Issue 50696 - Fix various UI bugs
https://bugzilla.redhat.com/show_bug.cgi?id=1751004
Bug 1751004 - Log Settings "Create New Log Every" takes non integer as input, it even takes alphabets
https://bugzilla.redhat.com/show_bug.cgi?id=1748349
Bug 1748349 - 'View objectclass' modal dialog doesn't have all controls disabled
https://bugzilla.redhat.com/show_bug.cgi?id=1688614
Bug 1688614 - Chaining Configuration Error: Cockpit had an unexpected internal error
https://bugzilla.redhat.com/show_bug.cgi?id=1748355
Bug 1748355 - LDAPI and Autobind configuration should have a warning
https://bugzilla.redhat.com/show_bug.cgi?id=1751157
Bug 1751157 - Cannot Create Database Link
https://bugzilla.redhat.com/show_bug.cgi?id=1751011
Bug 1751011 - DS instance can be easily destroyed by changing non existing Directory Manager DN
https://bugzilla.redhat.com/show_bug.cgi?id=1688663
Bug 1688663 - Cockpit: Enable Replication failed with error "Failed to add replication manager because the base DN of the entry does not exist"
https://bugzilla.redhat.com/show_bug.cgi?id=1751035
Bug 1751035 - Allow and Deny same Ciphers same time
relates: https://pagure.io/389-ds-base/issue/50696
Reviewed by: spichugi(Thanks!)
---
src/cockpit/389-console/src/database.jsx | 10 ++--
.../389-console/src/lib/database/chaining.jsx | 8 ++-
.../389-console/src/lib/database/suffix.jsx | 8 ++-
.../389-console/src/lib/monitor/serverMonitor.jsx | 2 +-
.../389-console/src/lib/replication/replModals.jsx | 23 +++++++--
.../389-console/src/lib/replication/replSuffix.jsx | 23 +++++++--
.../389-console/src/lib/security/ciphers.jsx | 58 +++++++++++++++++++---
src/cockpit/389-console/src/lib/tools.jsx | 3 ++
src/cockpit/389-console/src/schema.html | 34 ++++++-------
src/cockpit/389-console/src/servers.html | 6 +--
src/cockpit/389-console/src/servers.js | 25 ++++++----
src/lib389/lib389/cli_conf/backend.py | 16 ++++--
12 files changed, 160 insertions(+), 56 deletions(-)
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
index b1c3953..697eb14 100644
--- a/src/cockpit/389-console/src/database.jsx
+++ b/src/cockpit/389-console/src/database.jsx
@@ -212,8 +212,8 @@ export class Database extends React.Component {
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
- const config = JSON.parse(content);
- const availableOids = config.items.filter((el) => !this.state.chainingConfig.oidList.includes(el));
+ let config = JSON.parse(content);
+ let availableOids = config.items.filter((el) => !this.state.chainingConfig.oidList.includes(el));
this.setState((prevState) => (
{
chainingConfig: {
@@ -304,15 +304,19 @@ export class Database extends React.Component {
const config = JSON.parse(content);
let availableComps = config.attrs.nspossiblechainingcomponents;
let compList = [];
+ let oidList = [];
if ('nsactivechainingcomponents' in config.attrs) {
availableComps = config.attrs.nspossiblechainingcomponents.filter((el) => !config.attrs.nsactivechainingcomponents.includes(el));
compList = config.attrs.nsactivechainingcomponents;
}
+ if ('nstransmittedcontrols' in config.attrs) {
+ oidList = config.attrs.nstransmittedcontrols;
+ }
this.setState(() => (
{
chainingConfig: {
...this.state.chainingConfig,
- oidList: config.attrs.nstransmittedcontrols,
+ oidList: oidList,
compList: compList,
availableComps: availableComps
}
diff --git a/src/cockpit/389-console/src/lib/database/chaining.jsx b/src/cockpit/389-console/src/lib/database/chaining.jsx
index 749d414..63cf899 100644
--- a/src/cockpit/389-console/src/lib/database/chaining.jsx
+++ b/src/cockpit/389-console/src/lib/database/chaining.jsx
@@ -969,7 +969,13 @@ export class ChainingConfig extends React.Component {
<div>
<Row>
<Col sm={10} className="ds-word-wrap">
- <ControlLabel className="ds-suffix-header"><Icon type="fa" name="link" /> <b>{this.props.suffix}</b> (<i>{this.props.bename}</i>)</ControlLabel>
+ <ControlLabel className="ds-suffix-header">
+ <Icon type="fa" name="link" /> <b>{this.props.suffix}</b> (<i>{this.props.bename}</i>)
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh database link"
+ onClick={() => this.props.reload(this.props.suffix)}
+ />
+ </ControlLabel>
</Col>
<Col sm={2}>
<Button
diff --git a/src/cockpit/389-console/src/lib/database/suffix.jsx b/src/cockpit/389-console/src/lib/database/suffix.jsx
index 9be54a8..12c2565 100644
--- a/src/cockpit/389-console/src/lib/database/suffix.jsx
+++ b/src/cockpit/389-console/src/lib/database/suffix.jsx
@@ -760,7 +760,13 @@ export class Suffix extends React.Component {
<div id="suffix-page">
<Row>
<Col sm={10} className="ds-word-wrap">
- <ControlLabel className="ds-suffix-header"><Icon type="fa" name={suffixIcon} /> <b>{this.props.suffix}</b> (<i>{this.props.bename}</i>)</ControlLabel>
+ <ControlLabel className="ds-suffix-header">
+ <Icon type="fa" name={suffixIcon} /> {this.props.suffix} (<i>{this.props.bename}</i>)
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh suffix"
+ onClick={() => this.props.reload(this.props.suffix)}
+ />
+ </ControlLabel>
</Col>
<Col sm={2}>
<div>
diff --git a/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
index f87fb00..e330f82 100644
--- a/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
+++ b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
@@ -148,7 +148,7 @@ export class ServerMonitor extends React.Component {
</Row>
<Row className="ds-margin-top">
<Col componentClass={ControlLabel} sm={4}>
- Current Conections
+ Current Connections
</Col>
<Col sm={8}>
<input type="text" className="ds-input-auto" id="monitor-server-currentconnections" value={this.props.data.currentconnections} readOnly />
diff --git a/src/cockpit/389-console/src/lib/replication/replModals.jsx b/src/cockpit/389-console/src/lib/replication/replModals.jsx
index 0e7a0d9..4c15d71 100644
--- a/src/cockpit/389-console/src/lib/replication/replModals.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replModals.jsx
@@ -1279,11 +1279,10 @@ export class EnableReplModal extends React.Component {
Choose the replication role for this suffix. If it
is a Master replica then you must pick a unique ID
to identify it among the other Master replicas in your
- environment. You can optionally define the authentication
- information for this replicated suffix, either a Bind DN and
- Password, or a Group DN. The replication changelog will
- also automatically be created if it does not exist.
+ environment. The replication changelog will also
+ automatically be created if it does not exist.
</p>
+
<hr />
<Row className="ds-margin-top-lg">
<Col sm={3} componentClass={ControlLabel}>
@@ -1298,8 +1297,18 @@ export class EnableReplModal extends React.Component {
</Col>
</Row>
{replicaIDRow}
+ <p className="ds-margin-top-xxlg">
+ You can optionally define the authentication information
+ for this replicated suffix. Either a Manager DN and Password,
+ a Bind Group DN, or both, can be provideed. The Manager DN should
+ be an entry under "cn=config" and if it does not exist it will
+ be created, while the Bind Group DN is usually an existing
+ group located in the database suffix. Typically, just the
+ Manager DN and Password are used when enabling replication
+ for a suffix.
+ </p>
<hr />
- <Row className="ds-margin-top" title="The DN of the replication manager. If you supply a password the entry will be created in the server (it will also overwrite the entry is it already exists).">
+ <Row className="ds-margin-top-lg" title="The DN of the replication manager. If you supply a password the entry will be created in the server (it will also overwrite the entry is it already exists).">
<Col componentClass={ControlLabel} sm={4}>
Replication Manager DN
</Col>
@@ -1339,6 +1348,7 @@ export class EnableReplModal extends React.Component {
/>
</Col>
</Row>
+ <hr />
<Row className="ds-margin-top" title="The DN of a group that contains users that can perform replication updates">
<Col componentClass={ControlLabel} sm={4}>
Bind Group DN
@@ -1366,6 +1376,7 @@ export class EnableReplModal extends React.Component {
<Button
bsStyle="primary"
onClick={saveHandler}
+ disabled={this.props.disabled}
>
Enable Replication
</Button>
@@ -1463,6 +1474,7 @@ EnableReplModal.propTypes = {
handleChange: PropTypes.func,
saveHandler: PropTypes.func,
spinning: PropTypes.bool,
+ disabled: PropTypes.bool,
error: PropTypes.object,
};
@@ -1472,6 +1484,7 @@ EnableReplModal.defaultProps = {
handleChange: noop,
saveHandler: noop,
spinning: false,
+ disabled: false,
error: {},
};
diff --git a/src/cockpit/389-console/src/lib/replication/replSuffix.jsx b/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
index 0978c0c..a83ca37 100644
--- a/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
@@ -42,6 +42,7 @@ export class ReplSuffix extends React.Component {
enableBindPW: "",
enableBindPWConfirm: "",
enableBindGroupDN: "",
+ disabled: false, // Disable repl enable button
// Disable replication
showDisableReplModal: false,
disableChecked: false,
@@ -104,11 +105,12 @@ export class ReplSuffix extends React.Component {
let attr = e.target.id;
let valueErr = false;
let errObj = this.state.errObj;
+ let disable = false;
- if (attr == "enableBindDN" && value != "" && !valid_dn(value)) {
+ if (attr == "enableBindDN" && value != "" && (!valid_dn(value) || !value.includes(','))) {
valueErr = true;
}
- if (attr == "enableBindGroupDN" && value != "" && !valid_dn(value)) {
+ if (attr == "enableBindGroupDN" && value != "" && (!valid_dn(value) || !value.includes(','))) {
valueErr = true;
}
if (attr == "enableBindPW") {
@@ -127,10 +129,24 @@ export class ReplSuffix extends React.Component {
errObj.enableBindPWConfirm = false;
}
}
+
+ // Validate form and disable enable button if something is wrong.
+ if (valueErr) {
+ disable = true;
+ } else {
+ if ((attr != "enableBindPW" && attr != "enableBindPWConfirm" && this.state.enableBindPW != this.state.enableBindPWConfirm) ||
+ (this.state.enableBindDN != "" && attr != "enableBindDN" && (!valid_dn(this.state.enableBindDN) ||
+ !this.state.enableBindDN.includes(','))) ||
+ (this.state.enableBindGroupDN != "" && attr != "enableBindGroupDN" && (!valid_dn(this.state.enableBindGroupDN) ||
+ !this.state.enableBindGroupDN.includes(',')))) {
+ disable = true;
+ }
+ }
errObj[attr] = valueErr;
this.setState({
[attr]: value,
- errObj: errObj
+ errObj: errObj,
+ disabled: disable
});
}
@@ -395,6 +411,7 @@ export class ReplSuffix extends React.Component {
saveHandler={this.enableReplication}
spinning={this.state.addManagerSpinning}
role={this.state.enableRole}
+ disabled={this.state.disabled}
error={this.state.errObj}
/>
<DoubleConfirmModal
diff --git a/src/cockpit/389-console/src/lib/security/ciphers.jsx b/src/cockpit/389-console/src/lib/security/ciphers.jsx
index c07c0dc..c187586 100644
--- a/src/cockpit/389-console/src/lib/security/ciphers.jsx
+++ b/src/cockpit/389-console/src/lib/security/ciphers.jsx
@@ -22,16 +22,19 @@ export class Ciphers extends React.Component {
cipherPref: "default",
prefs: this.props.cipherPref,
saving: false,
+ availableCiphers: this.props.supportedCiphers,
};
this.handlePrefChange = this.handlePrefChange.bind(this);
this.saveCipherPref = this.saveCipherPref.bind(this);
+ this.handleCipherChange = this.handleCipherChange.bind(this);
}
componentWillMount () {
let cipherPref = "default";
let allowedCiphers = [];
let deniedCiphers = [];
+ let availableCiphers = this.props.supportedCiphers.slice(0); // Copy array
// Parse SSL cipher attributes (nsSSL3Ciphers)
if (this.props.cipherPref != "") {
@@ -57,12 +60,31 @@ export class Ciphers extends React.Component {
deniedCiphers.push(cipher.substring(1));
}
}
+
+ // Now modify the available list
+ for (let i = 0; i < availableCiphers.length; i++) {
+ for (let ii = 0; ii < allowedCiphers.length; ii++) {
+ if (availableCiphers[i] === allowedCiphers[ii]) {
+ availableCiphers.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ for (let ii = 0; ii < deniedCiphers.length; ii++) {
+ if (availableCiphers[i] === deniedCiphers[ii]) {
+ availableCiphers.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
}
this.setState({
cipherPref: cipherPref,
allowCiphers: allowedCiphers,
denyCiphers: deniedCiphers,
+ availableCiphers: availableCiphers,
});
}
@@ -117,6 +139,30 @@ export class Ciphers extends React.Component {
});
}
+ handleCipherChange (type, values) {
+ let availableCiphers = this.props.supportedCiphers.slice(0); // Copy array
+ for (let i = 0; i < availableCiphers.length; i++) {
+ for (let ci = 0; ci < values.length; ci++) {
+ if (availableCiphers[i] === values[ci]) {
+ availableCiphers.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
+ if (type == "allow") {
+ this.setState({
+ allowCiphers: values,
+ availableCiphers: availableCiphers
+ });
+ } else {
+ this.setState({
+ denyCiphers: values,
+ availableCiphers: availableCiphers
+ });
+ }
+ }
+
render () {
let supportedCiphers = [];
let enabledCiphers = [];
@@ -200,12 +246,10 @@ export class Ciphers extends React.Component {
<Typeahead
multiple
onChange={value => {
- this.setState({
- allowCiphers: value
- });
+ this.handleCipherChange("allow", value);
}}
selected={this.state.allowCiphers}
- options={this.props.supportedCiphers}
+ options={this.state.availableCiphers}
newSelectionPrefix="Add a cipher: "
placeholder="Type a cipher..."
id="allowCipher"
@@ -220,12 +264,10 @@ export class Ciphers extends React.Component {
<Typeahead
multiple
onChange={value => {
- this.setState({
- denyCiphers: value
- });
+ this.handleCipherChange("deny", value);
}}
selected={this.state.denyCiphers}
- options={this.props.supportedCiphers}
+ options={this.state.availableCiphers}
newSelectionPrefix="Add a cipher: "
placeholder="Type a cipher..."
id="denyCipher"
diff --git a/src/cockpit/389-console/src/lib/tools.jsx b/src/cockpit/389-console/src/lib/tools.jsx
index ca402f5..b37dd86 100644
--- a/src/cockpit/389-console/src/lib/tools.jsx
+++ b/src/cockpit/389-console/src/lib/tools.jsx
@@ -125,6 +125,9 @@ export function valid_port (val) {
export function valid_dn (dn) {
// Validate value is a valid DN (sanity validation)
+ if (dn.endsWith(',')) {
+ return false;
+ }
let dn_regex = new RegExp("^([A-Za-z]+=.*)");
let result = dn_regex.test(dn);
return result;
diff --git a/src/cockpit/389-console/src/schema.html b/src/cockpit/389-console/src/schema.html
index 36f61be..cb6baf9 100644
--- a/src/cockpit/389-console/src/schema.html
+++ b/src/cockpit/389-console/src/schema.html
@@ -79,27 +79,27 @@
<div class="ds-inline">
<div>
<label for="attr-name-view" class="ds-config-label-lrg" title="The attribute name"><b
- >Attribute Name</b></label><input class="ds-input" type="text" id="attr-name-view" size="40" readonly />
+ >Attribute Name</b></label><input class="ds-input" type="text" id="attr-name-view" size="40" disabled />
</div>
<div>
<label for="attr-desc-view" class="ds-config-label-lrg" title="The attribute description"><b
- >Description</b></label><input class="ds-input" type="text" id="attr-desc-view" size="40" readonly />
+ >Description</b></label><input class="ds-input" type="text" id="attr-desc-view" size="40" disabled />
</div>
<div>
<label for="attr-oid-view" class="ds-config-label-lrg" title="The attribute name"><b
- >OID</b></label><input class="ds-input" type="text" id="attr-oid-view" size="40" readonly />
+ >OID</b></label><input class="ds-input" type="text" id="attr-oid-view" size="40" disabled />
</div>
<div>
<label for="attr-parent-view" class="ds-config-label-lrg" title="The parent attribute"><b>Parent Attribute</b></label><input
- class="ds-input" type="text" id="attr-parent-view" size="40" readonly />
+ class="ds-input" type="text" id="attr-parent-view" size="40" disabled />
</div>
<div>
<label for="attr-syntax-view" class="ds-config-label-lrg" title="The attribute syntax"><b>Attribute Syntax</b></label><input
- class="ds-input" type="text" id="attr-syntax-view" size="40" readonly />
+ class="ds-input" type="text" id="attr-syntax-view" size="40" disabled />
</div>
<div>
<label for="attr-usage-view" class="ds-config-label-lrg" title="The parent attribute"><b>Attribute Usage</b></label><input
- class="ds-input" type="text" id="attr-usage-view" size="40" readonly />
+ class="ds-input" type="text" id="attr-usage-view" size="40" disabled />
</div>
<div>
<input type="checkbox" class="ds-config-checkbox" id="attr-multivalued-view" disabled="disabled" /><label
@@ -111,22 +111,22 @@
</div>
<div>
<label for="attr-alias-view" class="ds-config-label-lrg" title="The attribute alias list separated by space"><b
- >Attribute Aliases</b></label><input class="ds-input" type="text" id="attr-alias-view" size="40" readonly />
+ >Attribute Aliases</b></label><input class="ds-input" type="text" id="attr-alias-view" size="40" disabled />
</div>
<div class="panel panel-default ds-margin-top">
<div class="panel-heading"><strong>Matching rules</strong></div>
<div class="panel-body">
<div>
<label for="attr-eq-mr-select-view" class="ds-config-label-lrg"><b>Equality</b></label><input
- class="ds-input" type="text" id="attr-eq-mr-select-view" size="35" readonly />
+ class="ds-input" type="text" id="attr-eq-mr-select-view" size="35" disabled />
</div>
<div>
<label for="attr-order-mr-select-view" class="ds-config-label-lrg"><b>Ordering</b></label><input
- class="ds-input" type="text" id="attr-order-mr-select-view" size="35" readonly />
+ class="ds-input" type="text" id="attr-order-mr-select-view" size="35" disabled />
</div>
<div>
<label for="attr-sub-mr-select-view" class="ds-config-label-lrg"><b>Substring</b></label><input
- class="ds-input" type="text" id="attr-sub-mr-select-view" size="35" readonly />
+ class="ds-input" type="text" id="attr-sub-mr-select-view" size="35" disabled />
</div>
</div>
</div>
@@ -246,37 +246,37 @@
<div class="ds-inline">
<div>
<label for="oc-name-view" class="ds-config-label-lrg" title="The objectclass name"><b
- >Objectclass Name</b></label><input class="ds-input" type="text" id="oc-name-view" size="40" readonly />
+ >Objectclass Name</b></label><input class="ds-input" type="text" id="oc-name-view" size="40" disabled />
</div>
<div>
<label for="oc-desc-view" class="ds-config-label-lrg" title="The objectClass description"><b
- >Description</b></label><input class="ds-input" type="text" id="oc-desc-view" size="40" readonly/>
+ >Description</b></label><input class="ds-input" type="text" id="oc-desc-view" size="40" disabled/>
</div>
<div>
<label for="oc-oid-view" class="ds-config-label-lrg" title="Objectclass OID (optional)"><b
- >OID (optional)</b></label><input class="ds-input" value="" type="text" id="oc-oid-view" size="40" readonly/>
+ >OID (optional)</b></label><input class="ds-input" value="" type="text" id="oc-oid-view" size="40" disabled/>
</div>
<div>
<label for="oc-parent-view" class="ds-config-label-lrg" title="The parent objectclass"><b>Parent Objectclass</b></label><input
- class="ds-input" value="" type="text" id="oc-parent-view" size="40" readonly />
+ class="ds-input" value="" type="text" id="oc-parent-view" size="40" disabled />
</div>
<div>
<label for="oc-kind-view" class="ds-config-label-lrg" title="The parent objectclass"><b>Objectclass Kind</b></label><input
- class="ds-input" value="" type="text" id="oc-kind-view" size="40" readonly />
+ class="ds-input" value="" type="text" id="oc-kind-view" size="40" disabled />
</div>
<hr>
<div class="ds-container">
<div>
<label class="ds-config-label" for="oc-required-list-view" title=
"Attributes allowed by the objectclass"><b>Required Attributes</b></label>
- <select id="oc-required-list-view" class="ds-may-must-list" multiple>
+ <select id="oc-required-list-view" class="ds-may-must-list" multiple disabled>
</select>
</div>
<div class="ds-divider"></div>
<div>
<label class="ds-config-label" for="oc-allowed-list-view" title=
"Attributes allowed by the objectclass"><b>Allowed Attributes</b></label>
- <select id="oc-allowed-list-view" class="ds-may-must-list" multiple>
+ <select id="oc-allowed-list-view" class="ds-may-must-list" multiple disabled>
</select>
</div>
</div>
diff --git a/src/cockpit/389-console/src/servers.html b/src/cockpit/389-console/src/servers.html
index f60bd5d..5df11cd 100644
--- a/src/cockpit/389-console/src/servers.html
+++ b/src/cockpit/389-console/src/servers.html
@@ -136,7 +136,7 @@
<form>
<div>
<label for="nsslapd-rootdn" class="ds-config-label" title="The DN of the unrestricted directory manager (nsslapd-rootdn).">Directory Manager DN</label><input
- class="ds-input" type="text" readonly id="nsslapd-rootdn" value="cn=Directory Manager" size="40"/>
+ class="ds-input" type="text" disabled id="nsslapd-rootdn" value="cn=Directory Manager" size="40"/>
</div>
<div>
<label for="nsslapd-rootpw" class="ds-config-label" title="The Directory Manager password (nsslapd-rootpw).">Directory Manager Password</label><input
@@ -951,13 +951,13 @@
<div class="ldapi-attrs ds-inline" hidden>
<div>
<label for="nsslapd-ldapifilepath" class="ds-config-label" title="The Unix socket file (nsslapd-ldapifilepath). The UI requires this exact path so it is a read-only setting.">LDAPI Socket File Path</label><input
- class="ds-input" type="text" id="nsslapd-ldapifilepath" size="35" readonly/>
+ class="ds-input" type="text" id="nsslapd-ldapifilepath" size="35" disabled/>
</div>
<div class="ds-inline">
<div class="autobind-attrs">
<div>
<label for="nsslapd-ldapimaprootdn" class="ds-config-label" title="Map the Unix root entry to this Directory Manager DN (nsslapd-ldapimaprootdn). The UI requires this to be set to the current root DN so it is a read-only setting">DN to map "root" To</label><input
- class="ds-input" type="text" id="nsslapd-ldapimaprootdn" readonly size="35"/>
+ class="ds-input" type="text" id="nsslapd-ldapimaprootdn" disabled size="35"/>
</div>
<div>
<p></p>
diff --git a/src/cockpit/389-console/src/servers.js b/src/cockpit/389-console/src/servers.js
index 7e34a5a..9423a5d 100644
--- a/src/cockpit/389-console/src/servers.js
+++ b/src/cockpit/389-console/src/servers.js
@@ -318,19 +318,21 @@ function apply_mods(mods) {
}
let cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'config', 'replace'];
cmd.push(mod.attr + "=" + mod.val);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).then(function() {
+ cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function() {
config_values[mod.attr] = mod.val;
// Continue with next mods (if any))
apply_mods(mods);
- }, function(ex, data) {
- popup_err("Failed to update attribute: " + mod.attr, data);
- // Reset HTML for remaining values that have not been processed
- $("#" + mod.attr).val(config_values[mod.attr]);
- for (remaining in mods) {
- $("#" + remaining.attr).val(config_values[remaining.attr]);
- }
- check_inst_alive(0);
- return -1; // Stop on error
+ })
+ .fail(function(err) {
+ var err_obj = JSON.parse(err);
+ popup_err("Failed to update attribute: " + mod.attr, err_obj.info);
+ // Reset HTML for remaining values that have not been processed
+ $("#" + mod.attr).val(config_values[mod.attr]);
+ for (remaining in mods) {
+ $("#" + remaining.attr).val(config_values[remaining.attr]);
+ }
+ check_inst_alive(0);
+ return -1; // Stop on error
});
}
@@ -346,7 +348,8 @@ function delete_mods(mods) {
// Continue with next mods (if any))
delete_mods(mods);
}, function(ex, data) {
- popup_err("Failed to delete attribute: " + mod.attr, data);
+ var err_obj = JSON.parse(data);
+ popup_err("Failed to delete attribute: " + mod.attr, err_obj.info);
// Reset HTML for remaining values that have not been processed
$("#" + mod.attr).val(config_values[mod.attr]);
for (remaining in mods) {
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
index 93bf044..dc482f4 100644
--- a/src/lib389/lib389/cli_conf/backend.py
+++ b/src/lib389/lib389/cli_conf/backend.py
@@ -508,6 +508,16 @@ def db_config_set(inst, basedn, log, args):
print("Successfully updated database configuration")
+def _format_status(log, mtype, json=False):
+ if json:
+ print(mtype.get_status_json())
+ else:
+ status_dict = mtype.get_status()
+ log.info('dn: ' + mtype._dn)
+ for k, v in list(status_dict.items()):
+ # For each value in the multivalue attr
+ for vi in v:
+ log.info('{}: {}'.format(k, vi))
def get_monitor(inst, basedn, log, args):
if args.suffix is not None:
@@ -515,13 +525,13 @@ def get_monitor(inst, basedn, log, args):
be = _get_backend(inst, args.suffix)
monitor = be.get_monitor()
if monitor is not None:
- monitor.get_status(use_json=args.json)
+ _format_status(log, monitor, args.json)
return
raise ValueError("There was no monitor found for suffix '{}'".format(args.suffix))
else:
# Get the global database monitor entry
- db_mon = MonitorLDBM(inst)
- db_mon.get_status(use_json=args.json)
+ monitor = MonitorLDBM(inst)
+ _format_status(log, monitor, args.json)
def backend_add_index(inst, basedn, log, args):
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.4.1 updated: Issue 50696 - Fix various UI bugs
by pagure@pagure.io
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 becdf20 Issue 50696 - Fix various UI bugs
becdf20 is described below
commit becdf20b58bd0c296b88d290e22e8929739067f0
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Thu Nov 7 16:21:21 2019 -0500
Issue 50696 - Fix various UI bugs
https://bugzilla.redhat.com/show_bug.cgi?id=1751004
Bug 1751004 - Log Settings "Create New Log Every" takes non integer as input, it even takes alphabets
https://bugzilla.redhat.com/show_bug.cgi?id=1748349
Bug 1748349 - 'View objectclass' modal dialog doesn't have all controls disabled
https://bugzilla.redhat.com/show_bug.cgi?id=1688614
Bug 1688614 - Chaining Configuration Error: Cockpit had an unexpected internal error
https://bugzilla.redhat.com/show_bug.cgi?id=1748355
Bug 1748355 - LDAPI and Autobind configuration should have a warning
https://bugzilla.redhat.com/show_bug.cgi?id=1751157
Bug 1751157 - Cannot Create Database Link
https://bugzilla.redhat.com/show_bug.cgi?id=1751011
Bug 1751011 - DS instance can be easily destroyed by changing non existing Directory Manager DN
https://bugzilla.redhat.com/show_bug.cgi?id=1688663
Bug 1688663 - Cockpit: Enable Replication failed with error "Failed to add replication manager because the base DN of the entry does not exist"
https://bugzilla.redhat.com/show_bug.cgi?id=1751035
Bug 1751035 - Allow and Deny same Ciphers same time
relates: https://pagure.io/389-ds-base/issue/50696
Reviewed by: spichugi(Thanks!)
---
src/cockpit/389-console/src/database.jsx | 10 ++--
.../389-console/src/lib/database/chaining.jsx | 8 ++-
.../389-console/src/lib/database/suffix.jsx | 8 ++-
.../389-console/src/lib/monitor/serverMonitor.jsx | 2 +-
.../389-console/src/lib/replication/replModals.jsx | 23 +++++++--
.../389-console/src/lib/replication/replSuffix.jsx | 23 +++++++--
.../389-console/src/lib/security/ciphers.jsx | 58 +++++++++++++++++++---
src/cockpit/389-console/src/lib/tools.jsx | 3 ++
src/cockpit/389-console/src/schema.html | 34 ++++++-------
src/cockpit/389-console/src/servers.html | 6 +--
src/cockpit/389-console/src/servers.js | 25 ++++++----
src/lib389/lib389/cli_conf/backend.py | 16 ++++--
12 files changed, 160 insertions(+), 56 deletions(-)
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
index b1c3953..697eb14 100644
--- a/src/cockpit/389-console/src/database.jsx
+++ b/src/cockpit/389-console/src/database.jsx
@@ -212,8 +212,8 @@ export class Database extends React.Component {
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
- const config = JSON.parse(content);
- const availableOids = config.items.filter((el) => !this.state.chainingConfig.oidList.includes(el));
+ let config = JSON.parse(content);
+ let availableOids = config.items.filter((el) => !this.state.chainingConfig.oidList.includes(el));
this.setState((prevState) => (
{
chainingConfig: {
@@ -304,15 +304,19 @@ export class Database extends React.Component {
const config = JSON.parse(content);
let availableComps = config.attrs.nspossiblechainingcomponents;
let compList = [];
+ let oidList = [];
if ('nsactivechainingcomponents' in config.attrs) {
availableComps = config.attrs.nspossiblechainingcomponents.filter((el) => !config.attrs.nsactivechainingcomponents.includes(el));
compList = config.attrs.nsactivechainingcomponents;
}
+ if ('nstransmittedcontrols' in config.attrs) {
+ oidList = config.attrs.nstransmittedcontrols;
+ }
this.setState(() => (
{
chainingConfig: {
...this.state.chainingConfig,
- oidList: config.attrs.nstransmittedcontrols,
+ oidList: oidList,
compList: compList,
availableComps: availableComps
}
diff --git a/src/cockpit/389-console/src/lib/database/chaining.jsx b/src/cockpit/389-console/src/lib/database/chaining.jsx
index 749d414..63cf899 100644
--- a/src/cockpit/389-console/src/lib/database/chaining.jsx
+++ b/src/cockpit/389-console/src/lib/database/chaining.jsx
@@ -969,7 +969,13 @@ export class ChainingConfig extends React.Component {
<div>
<Row>
<Col sm={10} className="ds-word-wrap">
- <ControlLabel className="ds-suffix-header"><Icon type="fa" name="link" /> <b>{this.props.suffix}</b> (<i>{this.props.bename}</i>)</ControlLabel>
+ <ControlLabel className="ds-suffix-header">
+ <Icon type="fa" name="link" /> <b>{this.props.suffix}</b> (<i>{this.props.bename}</i>)
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh database link"
+ onClick={() => this.props.reload(this.props.suffix)}
+ />
+ </ControlLabel>
</Col>
<Col sm={2}>
<Button
diff --git a/src/cockpit/389-console/src/lib/database/suffix.jsx b/src/cockpit/389-console/src/lib/database/suffix.jsx
index 9be54a8..12c2565 100644
--- a/src/cockpit/389-console/src/lib/database/suffix.jsx
+++ b/src/cockpit/389-console/src/lib/database/suffix.jsx
@@ -760,7 +760,13 @@ export class Suffix extends React.Component {
<div id="suffix-page">
<Row>
<Col sm={10} className="ds-word-wrap">
- <ControlLabel className="ds-suffix-header"><Icon type="fa" name={suffixIcon} /> <b>{this.props.suffix}</b> (<i>{this.props.bename}</i>)</ControlLabel>
+ <ControlLabel className="ds-suffix-header">
+ <Icon type="fa" name={suffixIcon} /> {this.props.suffix} (<i>{this.props.bename}</i>)
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh suffix"
+ onClick={() => this.props.reload(this.props.suffix)}
+ />
+ </ControlLabel>
</Col>
<Col sm={2}>
<div>
diff --git a/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
index f87fb00..e330f82 100644
--- a/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
+++ b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
@@ -148,7 +148,7 @@ export class ServerMonitor extends React.Component {
</Row>
<Row className="ds-margin-top">
<Col componentClass={ControlLabel} sm={4}>
- Current Conections
+ Current Connections
</Col>
<Col sm={8}>
<input type="text" className="ds-input-auto" id="monitor-server-currentconnections" value={this.props.data.currentconnections} readOnly />
diff --git a/src/cockpit/389-console/src/lib/replication/replModals.jsx b/src/cockpit/389-console/src/lib/replication/replModals.jsx
index 0e7a0d9..4c15d71 100644
--- a/src/cockpit/389-console/src/lib/replication/replModals.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replModals.jsx
@@ -1279,11 +1279,10 @@ export class EnableReplModal extends React.Component {
Choose the replication role for this suffix. If it
is a Master replica then you must pick a unique ID
to identify it among the other Master replicas in your
- environment. You can optionally define the authentication
- information for this replicated suffix, either a Bind DN and
- Password, or a Group DN. The replication changelog will
- also automatically be created if it does not exist.
+ environment. The replication changelog will also
+ automatically be created if it does not exist.
</p>
+
<hr />
<Row className="ds-margin-top-lg">
<Col sm={3} componentClass={ControlLabel}>
@@ -1298,8 +1297,18 @@ export class EnableReplModal extends React.Component {
</Col>
</Row>
{replicaIDRow}
+ <p className="ds-margin-top-xxlg">
+ You can optionally define the authentication information
+ for this replicated suffix. Either a Manager DN and Password,
+ a Bind Group DN, or both, can be provideed. The Manager DN should
+ be an entry under "cn=config" and if it does not exist it will
+ be created, while the Bind Group DN is usually an existing
+ group located in the database suffix. Typically, just the
+ Manager DN and Password are used when enabling replication
+ for a suffix.
+ </p>
<hr />
- <Row className="ds-margin-top" title="The DN of the replication manager. If you supply a password the entry will be created in the server (it will also overwrite the entry is it already exists).">
+ <Row className="ds-margin-top-lg" title="The DN of the replication manager. If you supply a password the entry will be created in the server (it will also overwrite the entry is it already exists).">
<Col componentClass={ControlLabel} sm={4}>
Replication Manager DN
</Col>
@@ -1339,6 +1348,7 @@ export class EnableReplModal extends React.Component {
/>
</Col>
</Row>
+ <hr />
<Row className="ds-margin-top" title="The DN of a group that contains users that can perform replication updates">
<Col componentClass={ControlLabel} sm={4}>
Bind Group DN
@@ -1366,6 +1376,7 @@ export class EnableReplModal extends React.Component {
<Button
bsStyle="primary"
onClick={saveHandler}
+ disabled={this.props.disabled}
>
Enable Replication
</Button>
@@ -1463,6 +1474,7 @@ EnableReplModal.propTypes = {
handleChange: PropTypes.func,
saveHandler: PropTypes.func,
spinning: PropTypes.bool,
+ disabled: PropTypes.bool,
error: PropTypes.object,
};
@@ -1472,6 +1484,7 @@ EnableReplModal.defaultProps = {
handleChange: noop,
saveHandler: noop,
spinning: false,
+ disabled: false,
error: {},
};
diff --git a/src/cockpit/389-console/src/lib/replication/replSuffix.jsx b/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
index 0978c0c..a83ca37 100644
--- a/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
+++ b/src/cockpit/389-console/src/lib/replication/replSuffix.jsx
@@ -42,6 +42,7 @@ export class ReplSuffix extends React.Component {
enableBindPW: "",
enableBindPWConfirm: "",
enableBindGroupDN: "",
+ disabled: false, // Disable repl enable button
// Disable replication
showDisableReplModal: false,
disableChecked: false,
@@ -104,11 +105,12 @@ export class ReplSuffix extends React.Component {
let attr = e.target.id;
let valueErr = false;
let errObj = this.state.errObj;
+ let disable = false;
- if (attr == "enableBindDN" && value != "" && !valid_dn(value)) {
+ if (attr == "enableBindDN" && value != "" && (!valid_dn(value) || !value.includes(','))) {
valueErr = true;
}
- if (attr == "enableBindGroupDN" && value != "" && !valid_dn(value)) {
+ if (attr == "enableBindGroupDN" && value != "" && (!valid_dn(value) || !value.includes(','))) {
valueErr = true;
}
if (attr == "enableBindPW") {
@@ -127,10 +129,24 @@ export class ReplSuffix extends React.Component {
errObj.enableBindPWConfirm = false;
}
}
+
+ // Validate form and disable enable button if something is wrong.
+ if (valueErr) {
+ disable = true;
+ } else {
+ if ((attr != "enableBindPW" && attr != "enableBindPWConfirm" && this.state.enableBindPW != this.state.enableBindPWConfirm) ||
+ (this.state.enableBindDN != "" && attr != "enableBindDN" && (!valid_dn(this.state.enableBindDN) ||
+ !this.state.enableBindDN.includes(','))) ||
+ (this.state.enableBindGroupDN != "" && attr != "enableBindGroupDN" && (!valid_dn(this.state.enableBindGroupDN) ||
+ !this.state.enableBindGroupDN.includes(',')))) {
+ disable = true;
+ }
+ }
errObj[attr] = valueErr;
this.setState({
[attr]: value,
- errObj: errObj
+ errObj: errObj,
+ disabled: disable
});
}
@@ -395,6 +411,7 @@ export class ReplSuffix extends React.Component {
saveHandler={this.enableReplication}
spinning={this.state.addManagerSpinning}
role={this.state.enableRole}
+ disabled={this.state.disabled}
error={this.state.errObj}
/>
<DoubleConfirmModal
diff --git a/src/cockpit/389-console/src/lib/security/ciphers.jsx b/src/cockpit/389-console/src/lib/security/ciphers.jsx
index c07c0dc..c187586 100644
--- a/src/cockpit/389-console/src/lib/security/ciphers.jsx
+++ b/src/cockpit/389-console/src/lib/security/ciphers.jsx
@@ -22,16 +22,19 @@ export class Ciphers extends React.Component {
cipherPref: "default",
prefs: this.props.cipherPref,
saving: false,
+ availableCiphers: this.props.supportedCiphers,
};
this.handlePrefChange = this.handlePrefChange.bind(this);
this.saveCipherPref = this.saveCipherPref.bind(this);
+ this.handleCipherChange = this.handleCipherChange.bind(this);
}
componentWillMount () {
let cipherPref = "default";
let allowedCiphers = [];
let deniedCiphers = [];
+ let availableCiphers = this.props.supportedCiphers.slice(0); // Copy array
// Parse SSL cipher attributes (nsSSL3Ciphers)
if (this.props.cipherPref != "") {
@@ -57,12 +60,31 @@ export class Ciphers extends React.Component {
deniedCiphers.push(cipher.substring(1));
}
}
+
+ // Now modify the available list
+ for (let i = 0; i < availableCiphers.length; i++) {
+ for (let ii = 0; ii < allowedCiphers.length; ii++) {
+ if (availableCiphers[i] === allowedCiphers[ii]) {
+ availableCiphers.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ for (let ii = 0; ii < deniedCiphers.length; ii++) {
+ if (availableCiphers[i] === deniedCiphers[ii]) {
+ availableCiphers.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
}
this.setState({
cipherPref: cipherPref,
allowCiphers: allowedCiphers,
denyCiphers: deniedCiphers,
+ availableCiphers: availableCiphers,
});
}
@@ -117,6 +139,30 @@ export class Ciphers extends React.Component {
});
}
+ handleCipherChange (type, values) {
+ let availableCiphers = this.props.supportedCiphers.slice(0); // Copy array
+ for (let i = 0; i < availableCiphers.length; i++) {
+ for (let ci = 0; ci < values.length; ci++) {
+ if (availableCiphers[i] === values[ci]) {
+ availableCiphers.splice(i, 1);
+ i--;
+ break;
+ }
+ }
+ }
+ if (type == "allow") {
+ this.setState({
+ allowCiphers: values,
+ availableCiphers: availableCiphers
+ });
+ } else {
+ this.setState({
+ denyCiphers: values,
+ availableCiphers: availableCiphers
+ });
+ }
+ }
+
render () {
let supportedCiphers = [];
let enabledCiphers = [];
@@ -200,12 +246,10 @@ export class Ciphers extends React.Component {
<Typeahead
multiple
onChange={value => {
- this.setState({
- allowCiphers: value
- });
+ this.handleCipherChange("allow", value);
}}
selected={this.state.allowCiphers}
- options={this.props.supportedCiphers}
+ options={this.state.availableCiphers}
newSelectionPrefix="Add a cipher: "
placeholder="Type a cipher..."
id="allowCipher"
@@ -220,12 +264,10 @@ export class Ciphers extends React.Component {
<Typeahead
multiple
onChange={value => {
- this.setState({
- denyCiphers: value
- });
+ this.handleCipherChange("deny", value);
}}
selected={this.state.denyCiphers}
- options={this.props.supportedCiphers}
+ options={this.state.availableCiphers}
newSelectionPrefix="Add a cipher: "
placeholder="Type a cipher..."
id="denyCipher"
diff --git a/src/cockpit/389-console/src/lib/tools.jsx b/src/cockpit/389-console/src/lib/tools.jsx
index ca402f5..b37dd86 100644
--- a/src/cockpit/389-console/src/lib/tools.jsx
+++ b/src/cockpit/389-console/src/lib/tools.jsx
@@ -125,6 +125,9 @@ export function valid_port (val) {
export function valid_dn (dn) {
// Validate value is a valid DN (sanity validation)
+ if (dn.endsWith(',')) {
+ return false;
+ }
let dn_regex = new RegExp("^([A-Za-z]+=.*)");
let result = dn_regex.test(dn);
return result;
diff --git a/src/cockpit/389-console/src/schema.html b/src/cockpit/389-console/src/schema.html
index 36f61be..cb6baf9 100644
--- a/src/cockpit/389-console/src/schema.html
+++ b/src/cockpit/389-console/src/schema.html
@@ -79,27 +79,27 @@
<div class="ds-inline">
<div>
<label for="attr-name-view" class="ds-config-label-lrg" title="The attribute name"><b
- >Attribute Name</b></label><input class="ds-input" type="text" id="attr-name-view" size="40" readonly />
+ >Attribute Name</b></label><input class="ds-input" type="text" id="attr-name-view" size="40" disabled />
</div>
<div>
<label for="attr-desc-view" class="ds-config-label-lrg" title="The attribute description"><b
- >Description</b></label><input class="ds-input" type="text" id="attr-desc-view" size="40" readonly />
+ >Description</b></label><input class="ds-input" type="text" id="attr-desc-view" size="40" disabled />
</div>
<div>
<label for="attr-oid-view" class="ds-config-label-lrg" title="The attribute name"><b
- >OID</b></label><input class="ds-input" type="text" id="attr-oid-view" size="40" readonly />
+ >OID</b></label><input class="ds-input" type="text" id="attr-oid-view" size="40" disabled />
</div>
<div>
<label for="attr-parent-view" class="ds-config-label-lrg" title="The parent attribute"><b>Parent Attribute</b></label><input
- class="ds-input" type="text" id="attr-parent-view" size="40" readonly />
+ class="ds-input" type="text" id="attr-parent-view" size="40" disabled />
</div>
<div>
<label for="attr-syntax-view" class="ds-config-label-lrg" title="The attribute syntax"><b>Attribute Syntax</b></label><input
- class="ds-input" type="text" id="attr-syntax-view" size="40" readonly />
+ class="ds-input" type="text" id="attr-syntax-view" size="40" disabled />
</div>
<div>
<label for="attr-usage-view" class="ds-config-label-lrg" title="The parent attribute"><b>Attribute Usage</b></label><input
- class="ds-input" type="text" id="attr-usage-view" size="40" readonly />
+ class="ds-input" type="text" id="attr-usage-view" size="40" disabled />
</div>
<div>
<input type="checkbox" class="ds-config-checkbox" id="attr-multivalued-view" disabled="disabled" /><label
@@ -111,22 +111,22 @@
</div>
<div>
<label for="attr-alias-view" class="ds-config-label-lrg" title="The attribute alias list separated by space"><b
- >Attribute Aliases</b></label><input class="ds-input" type="text" id="attr-alias-view" size="40" readonly />
+ >Attribute Aliases</b></label><input class="ds-input" type="text" id="attr-alias-view" size="40" disabled />
</div>
<div class="panel panel-default ds-margin-top">
<div class="panel-heading"><strong>Matching rules</strong></div>
<div class="panel-body">
<div>
<label for="attr-eq-mr-select-view" class="ds-config-label-lrg"><b>Equality</b></label><input
- class="ds-input" type="text" id="attr-eq-mr-select-view" size="35" readonly />
+ class="ds-input" type="text" id="attr-eq-mr-select-view" size="35" disabled />
</div>
<div>
<label for="attr-order-mr-select-view" class="ds-config-label-lrg"><b>Ordering</b></label><input
- class="ds-input" type="text" id="attr-order-mr-select-view" size="35" readonly />
+ class="ds-input" type="text" id="attr-order-mr-select-view" size="35" disabled />
</div>
<div>
<label for="attr-sub-mr-select-view" class="ds-config-label-lrg"><b>Substring</b></label><input
- class="ds-input" type="text" id="attr-sub-mr-select-view" size="35" readonly />
+ class="ds-input" type="text" id="attr-sub-mr-select-view" size="35" disabled />
</div>
</div>
</div>
@@ -246,37 +246,37 @@
<div class="ds-inline">
<div>
<label for="oc-name-view" class="ds-config-label-lrg" title="The objectclass name"><b
- >Objectclass Name</b></label><input class="ds-input" type="text" id="oc-name-view" size="40" readonly />
+ >Objectclass Name</b></label><input class="ds-input" type="text" id="oc-name-view" size="40" disabled />
</div>
<div>
<label for="oc-desc-view" class="ds-config-label-lrg" title="The objectClass description"><b
- >Description</b></label><input class="ds-input" type="text" id="oc-desc-view" size="40" readonly/>
+ >Description</b></label><input class="ds-input" type="text" id="oc-desc-view" size="40" disabled/>
</div>
<div>
<label for="oc-oid-view" class="ds-config-label-lrg" title="Objectclass OID (optional)"><b
- >OID (optional)</b></label><input class="ds-input" value="" type="text" id="oc-oid-view" size="40" readonly/>
+ >OID (optional)</b></label><input class="ds-input" value="" type="text" id="oc-oid-view" size="40" disabled/>
</div>
<div>
<label for="oc-parent-view" class="ds-config-label-lrg" title="The parent objectclass"><b>Parent Objectclass</b></label><input
- class="ds-input" value="" type="text" id="oc-parent-view" size="40" readonly />
+ class="ds-input" value="" type="text" id="oc-parent-view" size="40" disabled />
</div>
<div>
<label for="oc-kind-view" class="ds-config-label-lrg" title="The parent objectclass"><b>Objectclass Kind</b></label><input
- class="ds-input" value="" type="text" id="oc-kind-view" size="40" readonly />
+ class="ds-input" value="" type="text" id="oc-kind-view" size="40" disabled />
</div>
<hr>
<div class="ds-container">
<div>
<label class="ds-config-label" for="oc-required-list-view" title=
"Attributes allowed by the objectclass"><b>Required Attributes</b></label>
- <select id="oc-required-list-view" class="ds-may-must-list" multiple>
+ <select id="oc-required-list-view" class="ds-may-must-list" multiple disabled>
</select>
</div>
<div class="ds-divider"></div>
<div>
<label class="ds-config-label" for="oc-allowed-list-view" title=
"Attributes allowed by the objectclass"><b>Allowed Attributes</b></label>
- <select id="oc-allowed-list-view" class="ds-may-must-list" multiple>
+ <select id="oc-allowed-list-view" class="ds-may-must-list" multiple disabled>
</select>
</div>
</div>
diff --git a/src/cockpit/389-console/src/servers.html b/src/cockpit/389-console/src/servers.html
index f60bd5d..5df11cd 100644
--- a/src/cockpit/389-console/src/servers.html
+++ b/src/cockpit/389-console/src/servers.html
@@ -136,7 +136,7 @@
<form>
<div>
<label for="nsslapd-rootdn" class="ds-config-label" title="The DN of the unrestricted directory manager (nsslapd-rootdn).">Directory Manager DN</label><input
- class="ds-input" type="text" readonly id="nsslapd-rootdn" value="cn=Directory Manager" size="40"/>
+ class="ds-input" type="text" disabled id="nsslapd-rootdn" value="cn=Directory Manager" size="40"/>
</div>
<div>
<label for="nsslapd-rootpw" class="ds-config-label" title="The Directory Manager password (nsslapd-rootpw).">Directory Manager Password</label><input
@@ -951,13 +951,13 @@
<div class="ldapi-attrs ds-inline" hidden>
<div>
<label for="nsslapd-ldapifilepath" class="ds-config-label" title="The Unix socket file (nsslapd-ldapifilepath). The UI requires this exact path so it is a read-only setting.">LDAPI Socket File Path</label><input
- class="ds-input" type="text" id="nsslapd-ldapifilepath" size="35" readonly/>
+ class="ds-input" type="text" id="nsslapd-ldapifilepath" size="35" disabled/>
</div>
<div class="ds-inline">
<div class="autobind-attrs">
<div>
<label for="nsslapd-ldapimaprootdn" class="ds-config-label" title="Map the Unix root entry to this Directory Manager DN (nsslapd-ldapimaprootdn). The UI requires this to be set to the current root DN so it is a read-only setting">DN to map "root" To</label><input
- class="ds-input" type="text" id="nsslapd-ldapimaprootdn" readonly size="35"/>
+ class="ds-input" type="text" id="nsslapd-ldapimaprootdn" disabled size="35"/>
</div>
<div>
<p></p>
diff --git a/src/cockpit/389-console/src/servers.js b/src/cockpit/389-console/src/servers.js
index 7e34a5a..9423a5d 100644
--- a/src/cockpit/389-console/src/servers.js
+++ b/src/cockpit/389-console/src/servers.js
@@ -318,19 +318,21 @@ function apply_mods(mods) {
}
let cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket', 'config', 'replace'];
cmd.push(mod.attr + "=" + mod.val);
- cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).then(function() {
+ cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function() {
config_values[mod.attr] = mod.val;
// Continue with next mods (if any))
apply_mods(mods);
- }, function(ex, data) {
- popup_err("Failed to update attribute: " + mod.attr, data);
- // Reset HTML for remaining values that have not been processed
- $("#" + mod.attr).val(config_values[mod.attr]);
- for (remaining in mods) {
- $("#" + remaining.attr).val(config_values[remaining.attr]);
- }
- check_inst_alive(0);
- return -1; // Stop on error
+ })
+ .fail(function(err) {
+ var err_obj = JSON.parse(err);
+ popup_err("Failed to update attribute: " + mod.attr, err_obj.info);
+ // Reset HTML for remaining values that have not been processed
+ $("#" + mod.attr).val(config_values[mod.attr]);
+ for (remaining in mods) {
+ $("#" + remaining.attr).val(config_values[remaining.attr]);
+ }
+ check_inst_alive(0);
+ return -1; // Stop on error
});
}
@@ -346,7 +348,8 @@ function delete_mods(mods) {
// Continue with next mods (if any))
delete_mods(mods);
}, function(ex, data) {
- popup_err("Failed to delete attribute: " + mod.attr, data);
+ var err_obj = JSON.parse(data);
+ popup_err("Failed to delete attribute: " + mod.attr, err_obj.info);
// Reset HTML for remaining values that have not been processed
$("#" + mod.attr).val(config_values[mod.attr]);
for (remaining in mods) {
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
index 93bf044..dc482f4 100644
--- a/src/lib389/lib389/cli_conf/backend.py
+++ b/src/lib389/lib389/cli_conf/backend.py
@@ -508,6 +508,16 @@ def db_config_set(inst, basedn, log, args):
print("Successfully updated database configuration")
+def _format_status(log, mtype, json=False):
+ if json:
+ print(mtype.get_status_json())
+ else:
+ status_dict = mtype.get_status()
+ log.info('dn: ' + mtype._dn)
+ for k, v in list(status_dict.items()):
+ # For each value in the multivalue attr
+ for vi in v:
+ log.info('{}: {}'.format(k, vi))
def get_monitor(inst, basedn, log, args):
if args.suffix is not None:
@@ -515,13 +525,13 @@ def get_monitor(inst, basedn, log, args):
be = _get_backend(inst, args.suffix)
monitor = be.get_monitor()
if monitor is not None:
- monitor.get_status(use_json=args.json)
+ _format_status(log, monitor, args.json)
return
raise ValueError("There was no monitor found for suffix '{}'".format(args.suffix))
else:
# Get the global database monitor entry
- db_mon = MonitorLDBM(inst)
- db_mon.get_status(use_json=args.json)
+ monitor = MonitorLDBM(inst)
+ _format_status(log, monitor, args.json)
def backend_add_index(inst, basedn, log, args):
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months
[389-ds-base] branch 389-ds-base-1.4.0 updated: Issue 50689 - Failed db restore task does not report an error
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.4.0
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.4.0 by this push:
new 1697873 Issue 50689 - Failed db restore task does not report an error
1697873 is described below
commit 1697873439a962fc0aab86b27885ddca493cf332
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Mon Nov 4 15:45:55 2019 -0500
Issue 50689 - Failed db restore task does not report an error
Bug Description: If you have a back up that contains a backend that
is not configured the restore fails, but a success
return code is returned to the client. This happens
becuase the return code gets overwritten after the
failure.
Fix Description: Preserve the error code upon failure and properly update
the task exit code.
relates: https://pagure.io/389-ds-base/issue/50689
Reviewed by: tboardaz & lkrispen(Thanks!!)
Never rewrite the orginal error code
---
dirsrvtests/tests/suites/backups/backup_test.py | 73 +++++++++++++++++++++++++
ldap/servers/slapd/back-ldbm/archive.c | 42 +++++++-------
ldap/servers/slapd/back-ldbm/dblayer.c | 23 ++++----
src/lib389/lib389/cli_conf/backup.py | 3 +-
4 files changed, 106 insertions(+), 35 deletions(-)
diff --git a/dirsrvtests/tests/suites/backups/backup_test.py b/dirsrvtests/tests/suites/backups/backup_test.py
new file mode 100644
index 0000000..e938914
--- /dev/null
+++ b/dirsrvtests/tests/suites/backups/backup_test.py
@@ -0,0 +1,73 @@
+import logging
+import pytest
+import os
+from datetime import datetime
+from lib389._constants import DEFAULT_SUFFIX, INSTALL_LATEST_CONFIG
+from lib389.properties import BACKEND_SAMPLE_ENTRIES, TASK_WAIT
+from lib389.topologies import topology_st as topo
+from lib389.backend import Backend
+from lib389.tasks import BackupTask, RestoreTask
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+
+def test_missing_backend(topo):
+ """Test that an error is returned when a restore is performed for a
+ backend that is no longer present.
+
+ :id: 889b8028-35cf-41d7-91f6-bc5193683646
+ :setup: Standalone Instance
+ :steps:
+ 1. Create a second backend
+ 2. Perform a back up
+ 3. Remove one of the backends from the config
+ 4. Perform a restore
+ :expectedresults:
+ 1. Success
+ 2. Success
+ 3. Success
+ 4. Failure
+ """
+
+ # Create a new backend
+ BE_NAME = 'backupRoot'
+ BE_SUFFIX = 'dc=back,dc=up'
+ props = {
+ 'cn': BE_NAME,
+ 'nsslapd-suffix': BE_SUFFIX,
+ BACKEND_SAMPLE_ENTRIES: INSTALL_LATEST_CONFIG
+ }
+ be = Backend(topo.standalone)
+ backend_entry = be.create(properties=props)
+
+ # perform backup
+ backup_dir_name = "backup-%s" % datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
+ archive = os.path.join(topo.standalone.ds_paths.backup_dir, backup_dir_name)
+ backup_task = BackupTask(topo.standalone)
+ task_properties = {'nsArchiveDir': archive}
+ backup_task.create(properties=task_properties)
+ backup_task.wait()
+ assert backup_task.get_exit_code() == 0
+
+ # Remove new backend
+ backend_entry.delete()
+
+ # Restore the backup - it should fail
+ restore_task = RestoreTask(topo.standalone)
+ task_properties = {'nsArchiveDir': archive}
+ restore_task.create(properties=task_properties)
+ restore_task.wait()
+ assert restore_task.get_exit_code() != 0
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main(["-s", CURRENT_FILE])
+
diff --git a/ldap/servers/slapd/back-ldbm/archive.c b/ldap/servers/slapd/back-ldbm/archive.c
index 1b06cf9..8ad635a 100644
--- a/ldap/servers/slapd/back-ldbm/archive.c
+++ b/ldap/servers/slapd/back-ldbm/archive.c
@@ -19,18 +19,18 @@ int
ldbm_back_archive2ldbm(Slapi_PBlock *pb)
{
struct ldbminfo *li;
- char *rawdirectory = NULL; /* -a <directory> */
- char *directory = NULL; /* normalized */
- char *backendname = NULL;
- int return_value = -1;
- int task_flags = 0;
- int run_from_cmdline = 0;
Slapi_Task *task;
- int is_old_to_new = 0;
ldbm_instance *inst = NULL;
char *dbversion = NULL;
char *dataversion = NULL;
- int value = 0;
+ int32_t value = 0;
+ char *rawdirectory = NULL; /* -a <directory> */
+ char *directory = NULL; /* normalized */
+ char *backendname = NULL;
+ int32_t return_value = -1;
+ int32_t task_flags = 0;
+ int32_t run_from_cmdline = 0;
+ int32_t is_old_to_new = 0;
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li);
slapi_pblock_get(pb, SLAPI_SEQ_VAL, &rawdirectory);
@@ -172,8 +172,7 @@ ldbm_back_archive2ldbm(Slapi_PBlock *pb)
"the backup set. error=%d (%s)\n",
return_value, dblayer_strerror(return_value));
if (task) {
- slapi_task_log_notice(task, "Failed to read the backup file set "
- "from %s",
+ slapi_task_log_notice(task, "Failed to read the backup file set from %s",
directory);
}
}
@@ -184,7 +183,7 @@ ldbm_back_archive2ldbm(Slapi_PBlock *pb)
char *p;
char c;
char *bakup_dir = NULL;
- int skipinit = SLAPI_UPGRADEDB_SKIPINIT;
+ int32_t skipinit = SLAPI_UPGRADEDB_SKIPINIT;
p = strrchr(directory, '/');
if (NULL == p) {
@@ -211,25 +210,26 @@ ldbm_back_archive2ldbm(Slapi_PBlock *pb)
return_value = ldbm_back_upgradedb(pb);
}
} else {
- ldbm_instance *inst;
Object *inst_obj;
- int ret;
+ int32_t ret;
if (0 != return_value) {
- /* error case (607331)
- * just to go back to the previous state if possible */
- if ((return_value = dblayer_start(li, DBLAYER_NORMAL_MODE))) {
+ /*
+ * error case (607331)
+ * just to go back to the previous state if possible (preserve
+ * original error for now)
+ */
+ if ((ret = dblayer_start(li, DBLAYER_NORMAL_MODE))) {
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_archive2ldbm", "Unable to to start database in [%s]\n",
li->li_directory);
if (task) {
- slapi_task_log_notice(task, "Failed to start the database in "
- "%s",
+ slapi_task_log_notice(task, "Failed to start the database in %s",
li->li_directory);
}
- goto out;
}
}
+
/* bring all backends and changelog back online */
plugin_call_plugins(pb, SLAPI_PLUGIN_BE_POST_OPEN_FN);
for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
@@ -241,8 +241,7 @@ ldbm_back_archive2ldbm(Slapi_PBlock *pb)
"ldbm_back_archive2ldbm", "Unable to restart '%s'\n",
inst->inst_name);
if (task) {
- slapi_task_log_notice(task, "Unable to restart '%s'",
- inst->inst_name);
+ slapi_task_log_notice(task, "Unable to restart '%s'", inst->inst_name);
}
} else {
slapi_mtn_be_enable(inst->inst_be);
@@ -250,6 +249,7 @@ ldbm_back_archive2ldbm(Slapi_PBlock *pb)
}
}
}
+
out:
if (run_from_cmdline && (0 == return_value)) {
dblayer_restore_file_update(li, directory);
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
index 1fee805..8c93119 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
@@ -6506,12 +6506,10 @@ dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bena
/* We check on the source staging area, no point in going further if it
* isn't there */
if (stat(src_dir, &sbuf) < 0) {
- slapi_log_err(SLAPI_LOG_ERR, "dblayer_restore", "Backup directory %s does not "
- "exist.\n",
+ slapi_log_err(SLAPI_LOG_ERR, "dblayer_restore", "Backup directory %s does not exist.\n",
src_dir);
if (task) {
- slapi_task_log_notice(task, "Restore: backup directory %s does not "
- "exist.\n",
+ slapi_task_log_notice(task, "Restore: backup directory %s does not exist.",
src_dir);
}
return LDAP_UNWILLING_TO_PERFORM;
@@ -6520,8 +6518,7 @@ dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bena
"a directory.\n",
src_dir);
if (task) {
- slapi_task_log_notice(task, "Restore: backup directory %s is not "
- "a directory.\n",
+ slapi_task_log_notice(task, "Restore: backup directory %s is not a directory.",
src_dir);
}
return LDAP_UNWILLING_TO_PERFORM;
@@ -6565,12 +6562,13 @@ dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bena
inst = ldbm_instance_find_by_name(li, (char *)direntry->name);
if (inst == NULL) {
slapi_log_err(SLAPI_LOG_ERR,
- "dblayer_restore", "Target server has no %s configured\n",
+ "dblayer_restore", "Target server has no backend (%s) configured\n",
direntry->name);
if (task) {
slapi_task_log_notice(task,
- "dblayer_restore - Target server has no %s configured\n",
+ "dblayer_restore - Target server has no backend (%s) configured",
direntry->name);
+ slapi_task_cancel(task, LDAP_UNWILLING_TO_PERFORM);
}
PR_CloseDir(dirhandle);
return_value = LDAP_UNWILLING_TO_PERFORM;
@@ -6581,7 +6579,7 @@ dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bena
slapi_log_err(SLAPI_LOG_ERR, "dblayer_restore",
"Parent directory is not set, aborting restore\n");
if (task) {
- slapi_task_log_notice(task, "dblayer_restore - Parent directory is not set, aborting restore\n");
+ slapi_task_log_notice(task, "dblayer_restore - Parent directory is not set, aborting restore");
}
PR_CloseDir(dirhandle);
return_value = LDAP_UNWILLING_TO_PERFORM;
@@ -6636,7 +6634,7 @@ dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bena
"dblayer_restore", "Failed to open the directory \"%s\"\n", real_src_dir);
if (task) {
slapi_task_log_notice(task,
- "Restore: failed to open the directory \"%s\"\n", real_src_dir);
+ "Restore: failed to open the directory \"%s\"", real_src_dir);
}
return_value = -1;
goto error_out;
@@ -6669,7 +6667,7 @@ dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bena
changelogdir);
if (task) {
slapi_task_log_notice(task,
- "Restore: broken changelog dir path %s\n",
+ "Restore: broken changelog dir path %s",
changelogdir);
}
goto error_out;
@@ -6778,8 +6776,7 @@ dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task, char *bena
char *dataversion = NULL;
if (dbversion_read(li, home_dir, &ldbmversion, &dataversion) != 0) {
- slapi_log_err(SLAPI_LOG_WARNING, "dblayer_restore", "Unable to read dbversion "
- "file in %s\n",
+ slapi_log_err(SLAPI_LOG_WARNING, "dblayer_restore", "Unable to read dbversion file in %s\n",
home_dir);
} else {
adjust_idl_switch(ldbmversion, li);
diff --git a/src/lib389/lib389/cli_conf/backup.py b/src/lib389/lib389/cli_conf/backup.py
index 1e73fba..c53a39b 100644
--- a/src/lib389/lib389/cli_conf/backup.py
+++ b/src/lib389/lib389/cli_conf/backup.py
@@ -26,11 +26,12 @@ def backup_restore(inst, basedn, log, args):
task = inst.restore_online(archive=args.archive, db_type=args.db_type)
task.wait()
result = task.get_exit_code()
+ task_log = task.get_task_log()
if task.is_complete() and result == 0:
log.info("The backup restore task has finished successfully")
else:
- raise ValueError("The backup restore task has failed with the error code: ({})".format(result))
+ raise ValueError("The backup restore task has failed with the error code: {}\n{}".format(result, task_log))
def create_parser(subparsers):
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
4 years, 4 months