[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50291 - Add monitor tab functionality to Cockpit 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 1d13ff2 Ticket 50291 - Add monitor tab functionality to Cockpit UI
1d13ff2 is described below
commit 1d13ff252cd1f9b672bd6399dd556c57bb4eace7
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Tue Apr 9 23:01:33 2019 -0400
Ticket 50291 - Add monitor tab functionality to Cockpit UI
Description: Added the backend functionality to the monitoring
tab.
Also returned all dsconf errors as json objects so
the UI could display friendly error messages
https://pagure.io/389-ds-base/issue/50291
Reviewed by: spichugi(Thanks!)
(cherry picked from commit ab94fc12e2dedf21c7784609600d60b9999e1ce4)
---
src/cockpit/389-console/src/css/ds.css | 98 +-
src/cockpit/389-console/src/database.jsx | 23 +-
src/cockpit/389-console/src/ds.js | 52 +-
src/cockpit/389-console/src/index.es6 | 13 +-
src/cockpit/389-console/src/index.html | 34 +-
.../src/lib/database/attrEncryption.jsx | 6 +-
.../389-console/src/lib/database/backups.jsx | 18 +-
.../389-console/src/lib/database/chaining.jsx | 25 +-
.../src/lib/database/databaseConfig.jsx | 5 +-
.../389-console/src/lib/database/indexes.jsx | 19 +-
.../389-console/src/lib/database/referrals.jsx | 6 +-
.../389-console/src/lib/database/suffix.jsx | 21 +-
.../389-console/src/lib/database/vlvIndexes.jsx | 21 +-
.../389-console/src/lib/monitor/accesslog.jsx | 117 ++
.../389-console/src/lib/monitor/auditfaillog.jsx | 117 ++
.../389-console/src/lib/monitor/auditlog.jsx | 117 ++
.../src/lib/monitor/chainingMonitor.jsx | 177 +++
.../389-console/src/lib/monitor/dbMonitor.jsx | 368 ++++++
.../389-console/src/lib/monitor/errorlog.jsx | 140 +++
.../389-console/src/lib/monitor/monitorModals.jsx | 559 +++++++++
.../389-console/src/lib/monitor/monitorTables.jsx | 1295 ++++++++++++++++++++
.../389-console/src/lib/monitor/replMonitor.jsx | 538 ++++++++
.../389-console/src/lib/monitor/serverMonitor.jsx | 161 +++
.../389-console/src/lib/monitor/snmpMonitor.jsx | 223 ++++
.../389-console/src/lib/monitor/suffixMonitor.jsx | 423 +++++++
src/cockpit/389-console/src/lib/notifications.jsx | 2 +-
src/cockpit/389-console/src/lib/tools.jsx | 47 +
src/cockpit/389-console/src/monitor.html | 916 --------------
src/cockpit/389-console/src/monitor.js | 398 ------
src/cockpit/389-console/src/monitor.jsx | 1187 ++++++++++++++++++
src/cockpit/389-console/src/plugins.jsx | 17 +-
src/cockpit/389-console/src/replication.html | 14 +-
src/cockpit/389-console/src/replication.js | 6 +-
src/cockpit/389-console/src/schema.html | 4 +-
src/cockpit/389-console/src/servers.html | 6 +-
src/cockpit/389-console/webpack.config.js | 2 -
src/lib389/cli/dsconf | 13 +-
src/lib389/lib389/_mapped_object.py | 15 +-
src/lib389/lib389/agreement.py | 85 +-
src/lib389/lib389/chaining.py | 14 +-
src/lib389/lib389/cli_base/__init__.py | 7 +-
src/lib389/lib389/cli_conf/backend.py | 52 +-
src/lib389/lib389/cli_conf/monitor.py | 88 ++
src/lib389/lib389/cli_conf/replication.py | 178 ++-
src/lib389/lib389/monitor.py | 83 +-
src/lib389/lib389/replica.py | 23 +-
46 files changed, 6116 insertions(+), 1617 deletions(-)
diff --git a/src/cockpit/389-console/src/css/ds.css b/src/cockpit/389-console/src/css/ds.css
index 6af009c..e0ceeb8 100644
--- a/src/cockpit/389-console/src/css/ds.css
+++ b/src/cockpit/389-console/src/css/ds.css
@@ -106,7 +106,7 @@
}
.ds-chart-right {
- margin-left: 90px;
+ margin-left: 65px;
}
.ds-chart-left {
@@ -233,6 +233,25 @@
line-height: 1;
}
+.ds-refresh {
+ background-color: #0088ce;
+ background-image: linear-gradient(to bottom,#39a5dc 0,#0088ce 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff39a5dc', endColorstr='#ff0088ce', GradientType=0);
+ border-color: #00659c;
+ color: #fff;
+ padding: 3px;
+ box-shadow: 0 2px 3px rgba(3,3,3,.1);
+ border-radius: 50%;
+ border: 1px solid transparent;
+ font-size: 13px !important;
+}
+
+.ds-refresh:hover {
+ color: DarkGray;
+ background-color: white;
+ background-image: none;
+}
+
.dataTables_wrapper {
padding: 0px !important;
margin-bottom: 10px !important;
@@ -241,7 +260,7 @@
td {
white-space: normal;
word-wrap: break-word !important;
- max-width: 400px !important;
+ max-width: 200px !important;
}
.ds-hr {
@@ -339,6 +358,12 @@ td {
padding-left: 5px;
}
+.ds-input-auto-good {
+ width: 100%;
+ border-color: green;
+ padding-left: 5px;
+}
+
.ds-input-right {
text-align: right;
}
@@ -385,6 +410,10 @@ td {
max-width: 600px;
}
+.ds-lag-report {
+ min-width: 800px !important;
+}
+
.ds-repl-mgr {
max-width: 600px !important;
}
@@ -578,10 +607,7 @@ td {
}
.ds-db-table {
- background-color: white !important;
- padding: 0px;
- border: 1px solid #909090;
- clear: both;
+ border: 1px solid #d1d1d1;
word-wrap: break-word !important;
text-align: center;
}
@@ -599,7 +625,6 @@ td {
.ds-table-header th {
text-align: center !important;
- background-color: white;
}
.ds-plugin-table {
@@ -1058,13 +1083,13 @@ textarea {
vertical-align: top;
width: 315px;
height: 80px;
- resize: none;
word-wrap: break-word !important;
line-height: 1;
}
.ds-agmt-textarea {
width: 100%;
+ font-family: monospace !important;
}
.ds-logarea {
@@ -1072,23 +1097,14 @@ textarea {
padding-top: 5px;
vertical-align: top;
width: 100% !important;
- height: 600px !important;
+ height: 500px;
max-height: 600px !important;
- resize: none;
word-wrap: break-word !important;
line-height: 1;
font-family: monospace !important;
overflow-y: scroll;
}
-/* Removes dotted outline border of the text */
-select {
- text-shadow: 0 0 0 #000 !important;
- max-height: 200px !important;
- line-height: 1;
- padding: 5px;
-}
-
option {
color: #181818;
}
@@ -1137,24 +1153,28 @@ option {
float: left;
}
-.ds-footer {
- background-color: #e5e5e5 !important;
+.ds-footer{
+ background-color: #f5f5f5 !important;
margin-left: -25px;
padding: 10px;
position: fixed;
bottom: 0;
width: 100%;
height: 50px;
- border-top: 1px solid #999 !important;
+ border-top: 1px solid #e2e2e2 !important;
}
-.ds-modal-footer {
+.modal-footer {
background-color: #f5f5f5 !important;
padding: 10px;
bottom: 0;
width: 100%;
height: 50px;
- border-top: 1px solid #999 !important;
+ border-top: .5px solid #e2e2e2 !important;
+}
+
+.modal-header {
+ border-bottom: .5px solid #e2e2e2 !important;
}
.ds-nav-bar {
@@ -1226,6 +1246,13 @@ option {
margin-top: 10px;
}
+.ds-margin-top-sm {
+ margin-top: 9px;
+}
+.ds-margin-top-med {
+ margin-top: 15px !important;
+}
+
.ds-margin-top-lg {
margin-top: 20px !important;
}
@@ -1406,6 +1433,10 @@ option {
margin-left: 40px !important;
}
+.ds-margin-left-piechart {
+ margin-left: 130px !important;
+}
+
.ds-nested-modal {
margin-top: 100px;
margin-left: 100px;
@@ -1466,10 +1497,6 @@ option {
position: relative;
}
-tbody:nth-child(even) {
- background: #f1f1f1;
-}
-
.ds-toolbar {
bottom: 10px;
}
@@ -1546,8 +1573,7 @@ tbody:nth-child(even) {
}
.ds-table-pagination {
- background-color: transparent !important;
- border: 1px solid #909090;
+ border: 1px solid #d1d1d1;
}
.ds-vlv-label {
@@ -1587,12 +1613,16 @@ tbody:nth-child(even) {
margin-bottom: 15px;
}
+.ds-header {
+ font-size: 16px;
+}
+
.ds-no-padding () {
padding: 0 !imporant;
}
.alert {
- max-width: 600px;
+ max-width: 750px;
}
.ds-confirm {
@@ -1622,3 +1652,11 @@ tbody:nth-child(even) {
border-color: #bee1f4;
display: block;
}
+
+input {
+ padding-left: 5px !important;
+}
+
+.ds-width-auto {
+ width: 100%;
+}
diff --git a/src/cockpit/389-console/src/database.jsx b/src/cockpit/389-console/src/database.jsx
index cbcb126..e5adf79 100644
--- a/src/cockpit/389-console/src/database.jsx
+++ b/src/cockpit/389-console/src/database.jsx
@@ -185,9 +185,10 @@ export class Database extends React.Component {
}), this.setState({configUpdated: 0}));
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.addNotification(
"error",
- `Error loading database configuration - ${err}`
+ `Error loading database configuration - ${errMsg.desc}`
);
});
}
@@ -271,9 +272,10 @@ export class Database extends React.Component {
), this.loadAvailableControls());
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.addNotification(
"error",
- `Error loading default chaining configuration - ${err}`
+ `Error loading default chaining configuration - ${errMsg.desc}`
);
this.setState({
loading: false
@@ -430,9 +432,10 @@ export class Database extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.addNotification(
"error",
- `Error getting chaining link configuration - ${err}`
+ `Error getting chaining link configuration - ${errMsg.desc}`
);
});
}
@@ -615,9 +618,10 @@ export class Database extends React.Component {
this.loadSuffixTree(false);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.addNotification(
"error",
- `Error creating suffix - ${err}`
+ `Error creating suffix - ${errMsg.desc}`
);
this.closeSuffixModal();
});
@@ -774,9 +778,10 @@ export class Database extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.addNotification(
"error",
- `Error loading indexes for ${suffix} - ${err}`
+ `Error loading indexes for ${suffix} - ${errMsg.desc}`
);
});
}
@@ -816,7 +821,7 @@ export class Database extends React.Component {
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
"backend", "suffix", "get", suffix
];
- log_cmd("loadSuffixConfig", "Load suffix config", cmd);
+ log_cmd("loadSuffix", "Load suffix config", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
@@ -928,9 +933,10 @@ export class Database extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.addNotification(
"error",
- `Error loading indexes for ${suffix} - ${err}`
+ `Error loading indexes for ${suffix} - ${errMsg.desc}`
);
this.setState({
suffixLoading: false
@@ -999,9 +1005,10 @@ export class Database extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.addNotification(
"error",
- `Failed to get attributes - ${err}`
+ `Failed to get attributes - ${errMsg.desc}`
);
});
}
diff --git a/src/cockpit/389-console/src/ds.js b/src/cockpit/389-console/src/ds.js
index 8d5e3dc..32a97dc 100644
--- a/src/cockpit/389-console/src/ds.js
+++ b/src/cockpit/389-console/src/ds.js
@@ -13,7 +13,7 @@ var db_page_loaded = 1;
var repl_page_loaded = 0;
var plugin_page_loaded = 1;
var schema_page_loaded = 0;
-var monitor_page_loaded = 0;
+var monitor_page_loaded = 1;
var config_loaded = 0;
// objects to store original values (used for comparing what changed when saving
@@ -118,18 +118,50 @@ function sort_list (sel) {
function get_date_string (timestamp) {
// Convert DS timestamp to a friendly string: 20180921142257Z -> 10/21/2018, 2:22:57 PM
- var year = timestamp.substr(0,4);
- var month = timestamp.substr(4,2);
- var day = timestamp.substr(6,2);
- var hour = timestamp.substr(8,2);
- var minute = timestamp.substr(10,2);
- var sec = timestamp.substr(12,2);
- var date = new Date(parseInt(year), parseInt(month), parseInt(day),
+ let year = timestamp.substr(0,4);
+ let month = timestamp.substr(4,2);
+ let day = timestamp.substr(6,2);
+ let hour = timestamp.substr(8,2);
+ let minute = timestamp.substr(10,2);
+ let sec = timestamp.substr(12,2);
+ let date = new Date(parseInt(year), parseInt(month), parseInt(day),
parseInt(hour), parseInt(minute), parseInt(sec));
return date.toLocaleString();
}
+function get_date_diff(start, end) {
+ // Get the start up date
+ let year = start.substr(0,4);
+ let month = start.substr(4,2);
+ let day = start.substr(6,2);
+ let hour = start.substr(8,2);
+ let minute = start.substr(10,2);
+ let sec = start.substr(12,2);
+ let startDate = new Date(parseInt(year), parseInt(month), parseInt(day),
+ parseInt(hour), parseInt(minute), parseInt(sec));
+
+ // Get the servers current date
+ year = end.substr(0,4);
+ month = end.substr(4,2);
+ day = end.substr(6,2);
+ hour = end.substr(8,2);
+ minute = end.substr(10,2);
+ sec = end.substr(12,2);
+ let currDate = new Date(parseInt(year), parseInt(month), parseInt(day),
+ parseInt(hour), parseInt(minute), parseInt(sec));
+
+ // Generate pretty elapsed time string
+ let seconds = Math.floor((startDate - (currDate))/1000);
+ let minutes = Math.floor(seconds/60);
+ let hours = Math.floor(minutes/60);
+ let days = Math.floor(hours/24);
+ hours = hours-(days*24);
+ minutes = minutes-(days*24*60)-(hours*60);
+ seconds = seconds-(days*24*60*60)-(hours*60*60)-(minutes*60);
+
+ return("${days} days, ${hours} hours, ${minutes} minutes, and ${seconds} seconds");
+}
function set_no_insts () {
@@ -437,4 +469,8 @@ $(window.document).ready(function() {
$(".all-pages").hide();
$("#database-content").show();
});
+ $("#monitor-tab").on("click", function() {
+ $(".all-pages").hide();
+ $("#monitor-content").show();
+ });
});
diff --git a/src/cockpit/389-console/src/index.es6 b/src/cockpit/389-console/src/index.es6
index 404cbb0..0483752 100644
--- a/src/cockpit/389-console/src/index.es6
+++ b/src/cockpit/389-console/src/index.es6
@@ -2,6 +2,7 @@ import React from "react";
import ReactDOM from "react-dom";
import { Plugins } from "./plugins.jsx";
import { Database } from "./database.jsx";
+import { Monitor } from "./monitor.jsx";
var serverIdElem;
@@ -15,19 +16,25 @@ function renderReactDOM(clear) {
.value.replace("slapd-", "");
}
let d = new Date();
- let n = d.getTime(); // might not be needed MARK
+ let tabKey = d.getTime();
// Plugins Tab
ReactDOM.render(
- <Plugins serverId={serverIdElem} key={n} />,
+ <Plugins serverId={serverIdElem} key={tabKey} />,
document.getElementById("plugins")
);
// Database tab
ReactDOM.render(
- <Database serverId={serverIdElem} key={n} />,
+ <Database serverId={serverIdElem} key={tabKey} />,
document.getElementById("database")
);
+
+ // Monitor tab
+ ReactDOM.render(
+ <Monitor serverId={serverIdElem} key={tabKey} />,
+ document.getElementById("monitor")
+ );
}
// We have to create the wrappers because this is no simple way
diff --git a/src/cockpit/389-console/src/index.html b/src/cockpit/389-console/src/index.html
index 96586d1..7c5dbf8 100644
--- a/src/cockpit/389-console/src/index.html
+++ b/src/cockpit/389-console/src/index.html
@@ -23,7 +23,6 @@
<script src="servers.js"></script>
<script src="security.js"></script>
<script src="replication.js"></script>
- <script src="monitor.js"></script>
<link href="static/bootstrap.min.css" rel="stylesheet">
<link href="static/jquery.dataTables.min.css" type="text/css" rel="stylesheet">
<link href="static/jquery.timepicker.min.css" type="text/css" rel="stylesheet">
@@ -117,7 +116,7 @@
<li><a href="#0" class="ds-nav-choice" id="repl-config-btn" parent-id="replication-tab">Configuration</a></li>
<li><a href="#0" class="ds-nav-choice" id="repl-agmts-btn" parent-id="replication-tab">Agreements</a></li>
<li><a href="#0" class="ds-nav-choice" id="repl-winsync-btn" parent-id="replication-tab">Winsync Agreements</a></li>
- <li><a href="#0" class="ds-nav-choice" id="repl-cleanallruv-btn" parent-id="replication-tab">CleanAllRUV Tasks</a></li>
+ <li><a href="#0" class="ds-nav-choice" id="repl-tasks-btn" parent-id="replication-tab">Replication Tasks</a></li>
</ul>
</li>
@@ -142,26 +141,10 @@
</li>
<!-- Monitoring navtab -->
- <li class="dropdown ds-nav-tab">
- <a href="#0" class="dropdown-toggle ds-tab-list" data-toggle="dropdown" id="monitor-tab">
+ <li class="ds-nav-tab">
+ <a href="#0" class="ds-tab-list ds-tab-standalone"id="monitor-tab">
Monitoring
- <b class="caret"></b>
</a>
- <ul class="dropdown-menu ds-nav-item">
- <li><a tabindex="-1" id="monitor-db-btn" class="ds-nav-choice" parent-id="monitor-tab" href="#0">Database Performance</a></li>
- <li class="dropdown-submenu">
- <a tabindex="-1" href="#0">Logging</a>
- <ul class="dropdown-menu">
- <li><a href="#0" class="ds-nav-choice" id="monitor-log-access-btn" parent-id="monitor-tab">Access Log</a></li>
- <li><a href="#0" class="ds-nav-choice" id="monitor-log-audit-btn" parent-id="monitor-tab">Audit Log</a></li>
- <li><a href="#0" class="ds-nav-choice" id="monitor-log-auditfail-btn" parent-id="monitor-tab">Audit Failure Log</a></li>
- <li><a href="#0" class="ds-nav-choice" id="monitor-log-errors-btn" parent-id="monitor-tab">Errors Log</a></li>
- </ul>
- </li>
- <li><a tabindex="-1" class="ds-nav-choice" parent-id="monitor-tab" id="monitor-repl-btn" href="#0">Replication</a></li>
- <li><a tabindex="-1" class="ds-nav-choice" parent-id="monitor-tab" id="monitor-server-btn" href="#0">Server Statistics</a></li>
- <li><a tabindex="-1" class="ds-nav-choice" parent-id="monitor-tab" id="monitor-snmp-btn" href="#0">SNMP Counters</a></li>
- </ul>
</li>
</ul>
</div>
@@ -281,7 +264,7 @@
<p><span class="spinner spinner-xs spinner-inline"></span> Reloading schema files...</p>
</div>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id ="schema-reload-btn">Reload Schema</button>
</div>
@@ -320,7 +303,7 @@
<p><span class="spinner spinner-xs spinner-inline"></span> Restoring the server...</p>
</div>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
@@ -382,7 +365,7 @@
</div>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="chaining-save">Create Link</button>
</div>
@@ -455,7 +438,7 @@
</div>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="create-inst-save">Create Instance</button>
</div>
@@ -487,7 +470,7 @@
<p><span class="spinner spinner-xs spinner-inline"></span> Backing up the server...</p>
</div>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="ds-backup-btn">Do Backup</button>
</div>
@@ -535,6 +518,7 @@
</div>
<div id="monitor-content" class="all-pages" hidden>
+ <div id="monitor"></div>
</div>
</div>
diff --git a/src/cockpit/389-console/src/lib/database/attrEncryption.jsx b/src/cockpit/389-console/src/lib/database/attrEncryption.jsx
index 6965d72..9bc86bc 100644
--- a/src/cockpit/389-console/src/lib/database/attrEncryption.jsx
+++ b/src/cockpit/389-console/src/lib/database/attrEncryption.jsx
@@ -74,10 +74,11 @@ export class AttrEncryption extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failed to delete encrypted attribute - ${err}`
+ `Failed to delete encrypted attribute - ${errMsg.desc}`
);
});
}
@@ -98,10 +99,11 @@ export class AttrEncryption extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failure deleting encrypted attribute - ${err}`
+ `Failure deleting encrypted attribute - ${errMsg.desc}`
);
});
}
diff --git a/src/cockpit/389-console/src/lib/database/backups.jsx b/src/cockpit/389-console/src/lib/database/backups.jsx
index 6ddcc44..065e8a1 100644
--- a/src/cockpit/389-console/src/lib/database/backups.jsx
+++ b/src/cockpit/389-console/src/lib/database/backups.jsx
@@ -251,10 +251,11 @@ export class Backups extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.closeLDIFSpinningModal();
this.props.addNotification(
"error",
- `Failure importing LDIF - ${err}`
+ `Failure importing LDIF - ${errMsg.desc}`
);
});
}
@@ -277,11 +278,12 @@ export class Backups extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.closeLDIFDeleteSpinningModal();
this.props.addNotification(
"error",
- `Failure deleting LDIF file - ${err}`
+ `Failure deleting LDIF file - ${errMsg.desc}`
);
});
}
@@ -312,11 +314,12 @@ export class Backups extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.closeBackupModal();
this.props.addNotification(
"error",
- `Failure backing up server - ${err}`
+ `Failure backing up server - ${errMsg.desc}`
);
});
}
@@ -339,10 +342,11 @@ export class Backups extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.closeRestoreSpinningModal();
this.props.addNotification(
"error",
- `Failure restoring up server - ${err}`
+ `Failure restoring up server - ${errMsg.desc}`
);
});
}
@@ -366,11 +370,12 @@ export class Backups extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.closeDelBackupSpinningModal();
this.props.addNotification(
"error",
- `Failure deleting backup - ${err}`
+ `Failure deleting backup - ${errMsg.desc}`
);
});
}
@@ -432,11 +437,12 @@ export class Backups extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.closeExportModal();
this.props.addNotification(
"error",
- `Error exporting database - ${err}`
+ `Error exporting database - ${errMsg.desc}`
);
this.setState({
showExportModal: false,
diff --git a/src/cockpit/389-console/src/lib/database/chaining.jsx b/src/cockpit/389-console/src/lib/database/chaining.jsx
index cf507b3..f20fca6 100644
--- a/src/cockpit/389-console/src/lib/database/chaining.jsx
+++ b/src/cockpit/389-console/src/lib/database/chaining.jsx
@@ -195,10 +195,11 @@ export class ChainingDatabaseConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.props.addNotification(
"error",
- `Error updating chaining configuration - ${err}`
+ `Error updating chaining configuration - ${errMsg.desc}`
);
});
}
@@ -255,10 +256,11 @@ export class ChainingDatabaseConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.props.addNotification(
"error",
- `Error updating chaining controls - ${err}`
+ `Error updating chaining controls - ${errMsg.desc}`
);
});
}
@@ -298,10 +300,11 @@ export class ChainingDatabaseConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.props.addNotification(
"error",
- `Error removing chaining controls - ${err}`
+ `Error removing chaining controls - ${errMsg.desc}`
);
});
}
@@ -370,10 +373,11 @@ export class ChainingDatabaseConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.props.addNotification(
"error",
- `Error updating chaining components - ${err}`
+ `Error updating chaining components - ${errMsg.desc}`
);
});
}
@@ -400,10 +404,11 @@ export class ChainingDatabaseConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.props.addNotification(
"error",
- `Error removing chaining components - ${err}`
+ `Error removing chaining components - ${errMsg.desc}`
);
});
}
@@ -832,10 +837,11 @@ export class ChainingConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failed to update link configuration - ${err}`
+ `Failed to update link configuration - ${errMsg.desc}`
);
});
}
@@ -857,10 +863,11 @@ export class ChainingConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.loadSuffixTree(true);
this.props.addNotification(
"error",
- `Failed to delete database link - ${err}`
+ `Failed to delete database link - ${errMsg.desc}`
);
});
}
@@ -1160,7 +1167,7 @@ export class ChainControlsModal extends React.Component {
</div>
</Form>
</Modal.Body>
- <Modal.Footer className="ds-modal-footerZZZ">
+ <Modal.Footer>
<Button
bsStyle="default"
className="btn-cancel"
@@ -1221,7 +1228,7 @@ export class ChainCompsModal extends React.Component {
</div>
</Form>
</Modal.Body>
- <Modal.Footer className="ds-modal-footer">
+ <Modal.Footer>
<Button
bsStyle="default"
className="btn-cancel"
diff --git a/src/cockpit/389-console/src/lib/database/databaseConfig.jsx b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
index a34316d..edb0557 100644
--- a/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
+++ b/src/cockpit/389-console/src/lib/database/databaseConfig.jsx
@@ -190,10 +190,11 @@ export class GlobalDatabaseConfig extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload();
this.props.addNotification(
"error",
- `Error updating configuration - ${err}`
+ `Error updating configuration - ${errMsg.desc}`
);
});
}
@@ -370,7 +371,7 @@ export class GlobalDatabaseConfig extends React.Component {
<p />
</div>
</CustomCollapse>
- <hr />
+ <p />
<div className="ds-save-btn">
<button className="btn btn-primary save-button"
onClick={this.save_db_config}>Save Configuration</button>
diff --git a/src/cockpit/389-console/src/lib/database/indexes.jsx b/src/cockpit/389-console/src/lib/database/indexes.jsx
index 34c246b..f8e157d 100644
--- a/src/cockpit/389-console/src/lib/database/indexes.jsx
+++ b/src/cockpit/389-console/src/lib/database/indexes.jsx
@@ -132,17 +132,19 @@ export class SuffixIndexes extends React.Component {
}
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.addNotification(
"error",
- `Failed to get attributes - ${err}`
+ `Failed to get attributes - ${errMsg.desc}`
);
});
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.addNotification(
"error",
- `Failed to get matching rules - ${err}`
+ `Failed to get matching rules - ${errMsg.desc}`
);
});
}
@@ -242,12 +244,12 @@ export class SuffixIndexes extends React.Component {
);
})
.fail(err => {
- // this.loadIndexes();
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.closeIndexModal();
this.props.addNotification(
"error",
- `Error creating index - ${err}`
+ `Error creating index - ${errMsg.desc}`
);
});
}
@@ -328,9 +330,10 @@ export class SuffixIndexes extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.addNotification(
"error",
- `Error indexing attribute ${attr} - ${err}`
+ `Error indexing attribute ${attr} - ${errMsg.desc}`
);
});
}
@@ -421,11 +424,12 @@ export class SuffixIndexes extends React.Component {
}
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.closeEditIndexModal();
this.props.addNotification(
"error",
- `Error editing index - ${err}`
+ `Error editing index - ${errMsg.desc}`
);
});
}
@@ -487,10 +491,11 @@ export class SuffixIndexes extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Error deleting index - ${err}`
+ `Error deleting index - ${errMsg.desc}`
);
});
}
diff --git a/src/cockpit/389-console/src/lib/database/referrals.jsx b/src/cockpit/389-console/src/lib/database/referrals.jsx
index d86c8c4..22f9c50 100644
--- a/src/cockpit/389-console/src/lib/database/referrals.jsx
+++ b/src/cockpit/389-console/src/lib/database/referrals.jsx
@@ -90,10 +90,11 @@ export class SuffixReferrals extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failure deleting referral - ${err}`
+ `Failure deleting referral - ${errMsg.desc}`
);
});
}
@@ -146,11 +147,12 @@ export class SuffixReferrals extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.closeRefModal();
this.props.addNotification(
"error",
- `Failure creating referral - ${err}`
+ `Failure creating referral - ${errMsg.desc}`
);
});
}
diff --git a/src/cockpit/389-console/src/lib/database/suffix.jsx b/src/cockpit/389-console/src/lib/database/suffix.jsx
index aa3b99c..9cfb95b 100644
--- a/src/cockpit/389-console/src/lib/database/suffix.jsx
+++ b/src/cockpit/389-console/src/lib/database/suffix.jsx
@@ -196,9 +196,10 @@ export class Suffix extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.addNotification(
"error",
- `Error importing LDIF file - ${err}`
+ `Error importing LDIF file - ${errMsg.desc}`
);
this.setState({
showImportModal: false
@@ -278,10 +279,11 @@ export class Suffix extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.loadLDIFs();
this.props.addNotification(
"error",
- `Error exporting database - ${err}`
+ `Error exporting database - ${errMsg.desc}`
);
this.setState({
showExportModal: false,
@@ -330,9 +332,10 @@ export class Suffix extends React.Component {
});
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.addNotification(
"error",
- `Failed to reindex database - ${err}`
+ `Failed to reindex database - ${errMsg.desc}`
);
this.setState({
showReindexModal: false,
@@ -405,11 +408,12 @@ export class Suffix extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.loadSuffixTree(false);
this.closeSubSuffixModal();
this.props.addNotification(
"error",
- `Error creating sub-suffix - ${err}`
+ `Error creating sub-suffix - ${errMsg.desc}`
);
});
}
@@ -527,11 +531,12 @@ export class Suffix extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.loadSuffixTree(false);
this.closeLinkModal();
this.props.addNotification(
"error",
- `Error creating database link - ${err}`
+ `Error creating database link - ${errMsg.desc}`
);
});
}
@@ -594,11 +599,12 @@ export class Suffix extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.loadSuffixTree(true);
this.closeLinkModal();
this.props.addNotification(
"error",
- `Error deleting database - ${err}`
+ `Error deleting database - ${errMsg.desc}`
);
});
}
@@ -655,10 +661,11 @@ export class Suffix extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Error updating suffix configuration - ${err}`
+ `Error updating suffix configuration - ${errMsg.desc}`
);
});
}
diff --git a/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx b/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
index 674f8ec..a4df2b9 100644
--- a/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
+++ b/src/cockpit/389-console/src/lib/database/vlvIndexes.jsx
@@ -224,11 +224,12 @@ export class VLVIndexes extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.closeVLVEditModal();
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failed to edit VLV search - ${err}`
+ `Failed to edit VLV search - ${errMsg.desc}`
);
});
}
@@ -273,11 +274,12 @@ export class VLVIndexes extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.closeVLVEditModal();
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failed to add VLV index entry - ${err}`
+ `Failed to add VLV index entry - ${errMsg.desc}`
);
});
}
@@ -304,11 +306,12 @@ export class VLVIndexes extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.closeVLVEditModal();
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failed to add VLV index entry - ${err}`
+ `Failed to add VLV index entry - ${errMsg.desc}`
);
});
}
@@ -391,17 +394,19 @@ export class VLVIndexes extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.addNotification(
"error",
- `Failed create VLV index entry - ${err}`
+ `Failed create VLV index entry - ${errMsg.desc}`
);
});
}
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.addNotification(
"error",
- `Failed create VLV search entry - ${err}`
+ `Failed create VLV search entry - ${errMsg.desc}`
);
});
this.closeVLVModal();
@@ -455,10 +460,11 @@ export class VLVIndexes extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failed to deletre VLV index - ${err}`
+ `Failed to deletre VLV index - ${errMsg.desc}`
);
});
}
@@ -492,10 +498,11 @@ export class VLVIndexes extends React.Component {
);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
this.props.reload(this.props.suffix);
this.props.addNotification(
"error",
- `Failed to index VLV index - ${err}`
+ `Failed to index VLV index - ${errMsg.desc}`
);
});
}
diff --git a/src/cockpit/389-console/src/lib/monitor/accesslog.jsx b/src/cockpit/389-console/src/lib/monitor/accesslog.jsx
new file mode 100644
index 0000000..e373c08
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/accesslog.jsx
@@ -0,0 +1,117 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ Spinner,
+ noop,
+ Row,
+ Col,
+ ControlLabel,
+ Icon,
+} from "patternfly-react";
+
+export class AccessLogMonitor extends React.Component {
+ componentDidUpdate () {
+ // Set the textarea to be scrolled down to the bottom
+ let textarea = document.getElementById('accesslog-area');
+ textarea.scrollTop = textarea.scrollHeight;
+ }
+
+ render() {
+ let spinner = "";
+ if (this.props.reloading) {
+ spinner =
+ <div>
+ <Spinner inline loading size="sm" />
+ Reloading access log...
+ </div>;
+ }
+ let contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ onChange={this.props.handleRefresh}
+ />;
+ if (this.props.refreshing) {
+ contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ defaultChecked onChange={this.props.handleRefresh}
+ />;
+ }
+
+ let selectLines =
+ <div>
+ <label htmlFor="accesslog-lines"> Log Lines To Show</label><select
+ className="btn btn-default dropdown ds-left-margin"
+ onChange={this.props.handleChange}
+ id="accesslog-lines" value={this.props.lines}>
+ <option>50</option>
+ <option>100</option>
+ <option>200</option>
+ <option>300</option>
+ <option>400</option>
+ <option>500</option>
+ <option>1000</option>
+ <option>2000</option>
+ <option>5000</option>
+ <option>10000</option>
+ <option>50000</option>
+ </select>
+ </div>;
+
+ return (
+ <div id="monitor-log-access-page" className="container-fluid">
+ <Row>
+ <Col sm={3}>
+ <ControlLabel className="ds-suffix-header">
+ Access Log
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh access log"
+ onClick={() => this.props.reload(this.props.reload)}
+ />
+ </ControlLabel>
+ </Col>
+ <Col sm={9} className="ds-float-left">
+ {spinner}
+ </Col>
+ </Row>
+ <p />
+ <Row>
+ <Col sm={6}>
+ {selectLines}
+ </Col>
+ <Col sm={6}>
+ <div className="ds-float-right">
+ <label>
+ {contRefreshCheckbox} Continuously Refresh
+ </label>
+ </div>
+ </Col>
+ </Row>
+ <textarea id="accesslog-area" className="ds-logarea" value={this.props.data} readOnly />
+ </div>
+ );
+ }
+}
+
+// Props and defaultProps
+
+AccessLogMonitor.propTypes = {
+ data: PropTypes.string,
+ handleChange: PropTypes.func,
+ handleRefresh: PropTypes.func,
+ reload: PropTypes.func,
+ reloading: PropTypes.bool,
+ refreshing: PropTypes.bool,
+ lines: PropTypes.string,
+};
+
+AccessLogMonitor.defaultProps = {
+ data: "",
+ handleChange: noop,
+ handleRefresh: noop,
+ reload: noop,
+ reloading: false,
+ refreshing: false,
+ line: "50"
+};
+
+export default AccessLogMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/auditfaillog.jsx b/src/cockpit/389-console/src/lib/monitor/auditfaillog.jsx
new file mode 100644
index 0000000..d533fcc
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/auditfaillog.jsx
@@ -0,0 +1,117 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ Spinner,
+ noop,
+ Row,
+ Col,
+ Icon,
+ ControlLabel
+} from "patternfly-react";
+
+export class AuditFailLogMonitor extends React.Component {
+ componentDidUpdate () {
+ // Set the textarea to be scrolled down to the bottom
+ let textarea = document.getElementById('auditfaillog-area');
+ textarea.scrollTop = textarea.scrollHeight;
+ }
+
+ render() {
+ let spinner = "";
+ if (this.props.reloading) {
+ spinner =
+ <div>
+ <Spinner inline loading size="sm" />
+ Reloading audit failure log...
+ </div>;
+ }
+ let contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ onChange={this.props.handleRefresh}
+ />;
+ if (this.props.refreshing) {
+ contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ defaultChecked onChange={this.props.handleRefresh}
+ />;
+ }
+
+ let selectLines =
+ <div>
+ <label htmlFor="auditfaillog-lines"> Log Lines To Show</label><select
+ className="btn btn-default dropdown ds-left-margin"
+ onChange={this.props.handleChange}
+ id="auditfaillog-lines" value={this.props.lines}>
+ <option>50</option>
+ <option>100</option>
+ <option>200</option>
+ <option>300</option>
+ <option>400</option>
+ <option>500</option>
+ <option>1000</option>
+ <option>2000</option>
+ <option>5000</option>
+ <option>10000</option>
+ <option>50000</option>
+ </select>
+ </div>;
+
+ return (
+ <div id="monitor-log-auditfail-page" className="container-fluid">
+ <Row>
+ <Col sm={3}>
+ <ControlLabel className="ds-suffix-header">
+ Audit Failure Log
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh audit failure log"
+ onClick={() => this.props.reload(this.props.reload)}
+ />
+ </ControlLabel>
+ </Col>
+ <Col sm={9} className="ds-float-left">
+ {spinner}
+ </Col>
+ </Row>
+ <p />
+ <Row>
+ <Col sm={6}>
+ {selectLines}
+ </Col>
+ <Col sm={6}>
+ <div className="ds-float-right">
+ <label>
+ {contRefreshCheckbox} Continuously Refresh
+ </label>
+ </div>
+ </Col>
+ </Row>
+ <textarea id="auditfaillog-area" className="ds-logarea" value={this.props.data} readOnly />
+ </div>
+ );
+ }
+}
+
+// Props and defaultProps
+
+AuditFailLogMonitor.propTypes = {
+ data: PropTypes.string,
+ handleChange: PropTypes.func,
+ handleRefresh: PropTypes.func,
+ reload: PropTypes.func,
+ reloading: PropTypes.bool,
+ refreshing: PropTypes.bool,
+ lines: PropTypes.string,
+};
+
+AuditFailLogMonitor.defaultProps = {
+ data: "",
+ handleChange: noop,
+ handleRefresh: noop,
+ reload: noop,
+ reloading: false,
+ refreshing: false,
+ line: "50"
+};
+
+export default AuditFailLogMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/auditlog.jsx b/src/cockpit/389-console/src/lib/monitor/auditlog.jsx
new file mode 100644
index 0000000..ae84c6b
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/auditlog.jsx
@@ -0,0 +1,117 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ Spinner,
+ noop,
+ Row,
+ Col,
+ Icon,
+ ControlLabel
+} from "patternfly-react";
+
+export class AuditLogMonitor extends React.Component {
+ componentDidUpdate () {
+ // Set the textarea to be scrolled down to the bottom
+ let textarea = document.getElementById('auditlog-area');
+ textarea.scrollTop = textarea.scrollHeight;
+ }
+
+ render() {
+ let spinner = "";
+ if (this.props.reloading) {
+ spinner =
+ <div>
+ <Spinner inline loading size="sm" />
+ Reloading audit log...
+ </div>;
+ }
+ let contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ onChange={this.props.handleRefresh}
+ />;
+ if (this.props.refreshing) {
+ contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ defaultChecked onChange={this.props.handleRefresh}
+ />;
+ }
+
+ let selectLines =
+ <div>
+ <label htmlFor="auditlog-lines"> Log Lines To Show</label><select
+ className="btn btn-default dropdown ds-left-margin"
+ onChange={this.props.handleChange}
+ id="auditlog-lines" value={this.props.lines}>
+ <option>50</option>
+ <option>100</option>
+ <option>200</option>
+ <option>300</option>
+ <option>400</option>
+ <option>500</option>
+ <option>1000</option>
+ <option>2000</option>
+ <option>5000</option>
+ <option>10000</option>
+ <option>50000</option>
+ </select>
+ </div>;
+
+ return (
+ <div id="monitor-log-audit-page" className="container-fluid">
+ <Row>
+ <Col sm={3}>
+ <ControlLabel className="ds-suffix-header">
+ Audit Log
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh audit log"
+ onClick={() => this.props.reload(this.props.reload)}
+ />
+ </ControlLabel>
+ </Col>
+ <Col sm={9} className="ds-float-left">
+ {spinner}
+ </Col>
+ </Row>
+ <p />
+ <Row>
+ <Col sm={6}>
+ {selectLines}
+ </Col>
+ <Col sm={6}>
+ <div className="ds-float-right">
+ <label>
+ {contRefreshCheckbox} Continuously Refresh
+ </label>
+ </div>
+ </Col>
+ </Row>
+ <textarea id="auditlog-area" className="ds-logarea" value={this.props.data} readOnly />
+ </div>
+ );
+ }
+}
+
+// Props and defaultProps
+
+AuditLogMonitor.propTypes = {
+ data: PropTypes.string,
+ handleChange: PropTypes.func,
+ handleRefresh: PropTypes.func,
+ reload: PropTypes.func,
+ reloading: PropTypes.bool,
+ refreshing: PropTypes.bool,
+ lines: PropTypes.string,
+};
+
+AuditLogMonitor.defaultProps = {
+ data: "",
+ handleChange: noop,
+ handleRefresh: noop,
+ reload: noop,
+ reloading: false,
+ refreshing: false,
+ line: "50"
+};
+
+export default AuditLogMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/chainingMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/chainingMonitor.jsx
new file mode 100644
index 0000000..9c108ff
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/chainingMonitor.jsx
@@ -0,0 +1,177 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ Row,
+ Col,
+ ControlLabel,
+ Icon,
+} from "patternfly-react";
+
+export class ChainingMonitor extends React.Component {
+ render() {
+ return (
+ <div id="monitor-server-page" className="container-fluid">
+ <Row>
+ <Col sm={12} className="ds-word-wrap">
+ <ControlLabel className="ds-suffix-header">
+ <Icon type="fa" name="link" /> {this.props.suffix} (<i>{this.props.bename}</i>)
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh chaining monitor"
+ onClick={() => this.props.reload(this.props.suffix)}
+ />
+ </ControlLabel>
+ </Col>
+ </Row>
+ <p />
+ <hr />
+ <div>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Add Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsaddcount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Delete Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsdeletecount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Modify Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsmodifycount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ ModRDN Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsrenamecount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Base Searches
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nssearchbasecount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ One-Level Searches
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nssearchonelevelcount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Subtree Searches
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nssearchsubtreecount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Abandon Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsabandoncount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Bind Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsbindcount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Unbind Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsunbindcount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Compare Operations
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nscomparecount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Outgoing Connections
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsopenopconnectioncount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Outgoing Bind Connections
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.nsopenbindconnectioncount} size="35" readOnly />
+ </Col>
+ </Row>
+ </div>
+ </div>
+ );
+ }
+}
+
+ChainingMonitor.propTypes = {
+ suffix: PropTypes.string,
+ bename: PropTypes.string,
+ data: PropTypes.object
+};
+
+ChainingMonitor.defaultProps = {
+ suffix: "",
+ bename: "",
+ data: {}
+};
+
+export default ChainingMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/dbMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/dbMonitor.jsx
new file mode 100644
index 0000000..f5449dc
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/dbMonitor.jsx
@@ -0,0 +1,368 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ DonutChart,
+ PieChart,
+ Nav,
+ NavItem,
+ TabContent,
+ TabPane,
+ TabContainer,
+ Row,
+ Col,
+ ControlLabel,
+ Icon,
+ noop,
+} from "patternfly-react";
+import d3 from "d3";
+
+export class DatabaseMonitor extends React.Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ activeKey: 1,
+ };
+ this.handleNavSelect = this.handleNavSelect.bind(this);
+ }
+
+ handleNavSelect(key) {
+ this.setState({ activeKey: key });
+ }
+
+ render() {
+ let badColor = "#d01c8b";
+ let warningColor = "#ffc107";
+ let goodColor = "#4dac26";
+ let emptyColor = "#d3d3d3";
+ let donutColorDB = goodColor;
+ let donutColorNDN = goodColor;
+ let donutColorNDNUtil = goodColor;
+ let donutColorNDNMiss = emptyColor;
+ let donutColorDBMiss = emptyColor;
+ let dbcachehit = parseInt(this.props.data.dbcachehitratio[0]);
+ let ndncachehit = parseInt(this.props.data.normalizeddncachehitratio[0]);
+ let ndncachemax = parseInt(this.props.data.maxnormalizeddncachesize[0]);
+ let ndncachecurr = parseInt(this.props.data.currentnormalizeddncachesize[0]);
+ let utilratio = Math.round((ndncachecurr / ndncachemax) * 100);
+
+ // Database cache
+ if (dbcachehit > 89) {
+ donutColorDB = goodColor;
+ } else if (dbcachehit > 74) {
+ donutColorDB = warningColor;
+ } else {
+ if (dbcachehit < 50) {
+ // Pie chart shows higher catagory, so we need to highlight the misses
+ donutColorDBMiss = badColor;
+ } else {
+ donutColorDB = badColor;
+ }
+ }
+ // NDN cache ratio
+ if (ndncachehit > 89) {
+ donutColorNDN = goodColor;
+ } else if (ndncachehit > 74) {
+ donutColorNDN = warningColor;
+ } else {
+ if (ndncachehit < 50) {
+ // Pie chart shows higher catagory, so we need to highlight the misses
+ donutColorNDNMiss = badColor;
+ } else {
+ donutColorNDN = badColor;
+ }
+ }
+ // NDN cache utilization
+ if (ndncachehit < 90) {
+ if (utilratio > 95) {
+ donutColorNDNUtil = badColor;
+ } else if (utilratio > 90) {
+ donutColorNDNUtil = warningColor;
+ }
+ }
+
+ return (
+ <div id="db-content" className="container-fluid">
+ <Row>
+ <Col sm={12} className="ds-word-wrap">
+ <ControlLabel className="ds-suffix-header">
+ Database Performance Statistics
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh database monitor"
+ onClick={this.props.reload}
+ />
+ </ControlLabel>
+ </Col>
+ </Row>
+ <TabContainer id="basic-tabs-pf" onSelect={this.handleNavSelect} activeKey={this.state.activeKey}>
+ <div>
+ <Nav bsClass="nav nav-tabs nav-tabs-pf">
+ <NavItem eventKey={1}>
+ <div dangerouslySetInnerHTML={{__html: 'Database Cache'}} />
+ </NavItem>
+ <NavItem eventKey={2}>
+ <div dangerouslySetInnerHTML={{__html: 'Normalized DN Cache'}} />
+ </NavItem>
+ </Nav>
+ <TabContent>
+
+ <TabPane eventKey={1}>
+ <div className="ds-margin-top-lg ds-margin-left-piechart">
+ <DonutChart
+ id="monitor-db-cache-hitratio-chart"
+ size={{width: 180, height: 120}}
+ data={{
+ columns: [['miss', 100 - dbcachehit], ['hit', dbcachehit]],
+ colors: {
+ 'hit': donutColorDB,
+ 'miss': donutColorDBMiss,
+ },
+ order: null,
+ }}
+ title={{type: 'percent'}}
+ legend={{show: true, position: 'right'}}
+ />
+ <b className="ds-left-margin">DB Cache Hit Ratio</b>
+ </div>
+ <hr />
+ <div>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Database Cache Hit Ratio
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dbcachehitratio} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Database Cache Tries
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dbcachetries} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Database Cache Hits
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dbcachehits} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Cache Pages Read
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dbcachepagein} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Cache Pages Written
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dbcachepageout} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Read-Only Page Evictions
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dbcacheroevict} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Read-Write Page Evictions
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dbcacherwevict} size="28" readOnly />
+ </Col>
+ </Row>
+ </div>
+ </TabPane>
+
+ <TabPane eventKey={2}>
+ <div className="ds-margin-top-lg">
+ <div className="ds-container">
+ <div className="ds-left-margin">
+ <DonutChart
+ id="monitor-db-cache-ndn-hitratio-chart"
+ size={{width: 180, height: 120}}
+ data={{
+ columns: [['miss', 100 - ndncachehit], ['hit', ndncachehit]],
+ colors: {
+ 'hit': donutColorNDN,
+ 'miss': donutColorNDNMiss,
+ },
+ order: null,
+ }}
+ title={{type: 'percent'}}
+ legend={{show: true, position: 'right'}}
+ />
+ <b>NDN Cache Hit Ratio</b>
+ </div>
+ <div className="ds-chart-right">
+ <PieChart
+ id="monitor-db-cache-ndn-util-chart"
+ size={{width: 180, height: 120}}
+ data={{
+ columns: [
+ ['Used', utilratio],
+ ['Unused', 100 - utilratio],
+ ],
+ colors: {
+ 'Used': donutColorNDNUtil,
+ 'Unused': emptyColor,
+ },
+ order: null,
+ }}
+ pie={{
+ label: {
+ format: function (value, ratio, id) {
+ return d3.format(',%')(value / 100);
+ }
+ }
+ }}
+ title={{type: 'pie'}}
+ legend={{show: true, position: 'right'}}
+ />
+ <b>NDN Cache Utilization</b>
+ <div>
+ (DN's in cache: <b>{this.props.data.currentnormalizeddncachecount}</b>)
+ </div>
+ </div>
+ </div>
+ <hr />
+ <div>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache Hit Ratio
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.normalizeddncachehitratio} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache Tries
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.normalizeddncachetries} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache Hits
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.normalizeddncachehits} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache Evictions
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.normalizeddncacheevictions} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache Max Size
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.maxnormalizeddncachesize} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Current Cache Size
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.currentnormalizeddncachesize} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache DN Count
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.currentnormalizeddncachecount} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache Thread Size
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.normalizeddncachethreadsize} size="28" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ NDN Cache Thread Slots
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.normalizeddncachethreadslots} size="28" readOnly />
+ </Col>
+ </Row>
+ </div>
+ </div>
+ </TabPane>
+ </TabContent>
+ </div>
+ </TabContainer>
+ </div>
+ );
+ }
+}
+
+// Prop types and defaults
+
+DatabaseMonitor.propTypes = {
+ data: PropTypes.object,
+ reload: PropTypes.func
+};
+
+DatabaseMonitor.defaultProps = {
+ data: {},
+ reload: noop
+};
+
+export default DatabaseMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/errorlog.jsx b/src/cockpit/389-console/src/lib/monitor/errorlog.jsx
new file mode 100644
index 0000000..335a6d6
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/errorlog.jsx
@@ -0,0 +1,140 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ Spinner,
+ ControlLabel,
+ noop,
+ Icon,
+ Row,
+ Col
+} from "patternfly-react";
+
+export class ErrorLogMonitor extends React.Component {
+ componentDidUpdate () {
+ // Set the textarea to be scrolled down to the bottom
+ let textarea = document.getElementById('errorslog-area');
+ textarea.scrollTop = textarea.scrollHeight;
+ }
+
+ render() {
+ let spinner = "";
+ if (this.props.reloading) {
+ spinner =
+ <div>
+ <Spinner inline loading size="sm" />
+ Reloading errors log...
+ </div>;
+ }
+ let contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ onChange={this.props.handleRefresh}
+ />;
+ if (this.props.refreshing) {
+ contRefreshCheckbox =
+ <input type="checkbox" className="ds-sm-left-margin"
+ defaultChecked onChange={this.props.handleRefresh}
+ />;
+ }
+
+ let selectLines =
+ <div>
+ <label htmlFor="errorlog-lines"> Log Lines To Show</label><select
+ className="btn btn-default dropdown ds-left-margin"
+ onChange={this.props.handleChange}
+ id="errorlog-lines" value={this.props.lines}>
+ <option>50</option>
+ <option>100</option>
+ <option>200</option>
+ <option>300</option>
+ <option>400</option>
+ <option>500</option>
+ <option>1000</option>
+ <option>2000</option>
+ <option>5000</option>
+ <option>10000</option>
+ <option>50000</option>
+ </select>
+ </div>;
+
+ return (
+ <div id="monitor-log-errors-page" className="container-fluid">
+ <Row>
+ <Col sm={3}>
+ <ControlLabel className="ds-suffix-header">
+ Errors Log
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh errors log"
+ onClick={() => this.props.reload(this.props.reload)}
+ />
+ </ControlLabel>
+ </Col>
+ <Col sm={9} className="ds-float-left">
+ {spinner}
+ </Col>
+ </Row>
+ <p />
+ <Row>
+ <Col sm={5}>
+ {selectLines}
+ </Col>
+ <Col sm={4}>
+ <div className="dropdown">
+ <label htmlFor="errorslog-sev-level">Filter</label><select
+ className="btn btn-default dropdown ds-left-margin"
+ onChange={this.props.handleSevLevel}>
+ <option>Everything</option>
+ <option>Error Messages</option>
+ <option>Info Messages</option>
+ <option disabled>──────────</option>
+ <option>Emergency</option>
+ <option>Alert</option>
+ <option>Critical</option>
+ <option>Error</option>
+ <option>Warning</option>
+ <option>Notice</option>
+ <option>Info</option>
+ <option>Debug</option>
+ </select>
+ </div>
+ </Col>
+ <Col sm={3}>
+ <div className="ds-float-right">
+ <label>
+ {contRefreshCheckbox} Continuously Refresh
+ </label>
+ </div>
+ </Col>
+ </Row>
+ <textarea id="errorslog-area" className="ds-logarea" value={this.props.data} readOnly />
+ </div>
+ );
+ }
+}
+
+// Props and defaultProps
+
+ErrorLogMonitor.propTypes = {
+ data: PropTypes.string,
+ handleChange: PropTypes.func,
+ reload: PropTypes.func,
+ reloading: PropTypes.bool,
+ handleSevLevel: PropTypes.func,
+ refreshing: PropTypes.bool,
+ handleRefresh: PropTypes.func,
+ lines: PropTypes.string
+
+};
+
+ErrorLogMonitor.defaultProps = {
+ data: "",
+ handleChange: noop,
+ reload: noop,
+ reloading: false,
+ handleSevLevel: noop,
+ refreshing: false,
+ handleRefresh: noop,
+ lines: "50"
+};
+
+export default ErrorLogMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/monitorModals.jsx b/src/cockpit/389-console/src/lib/monitor/monitorModals.jsx
new file mode 100644
index 0000000..a63c67a
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/monitorModals.jsx
@@ -0,0 +1,559 @@
+import React from "react";
+import {
+ Modal,
+ Row,
+ Col,
+ ControlLabel,
+ Icon,
+ Button,
+ Form,
+ noop,
+ Spinner,
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import { get_date_string } from "../tools.jsx";
+import { LagReportTable } from "./monitorTables.jsx";
+import "../../css/ds.css";
+
+class ReplLoginModal extends React.Component {
+ render() {
+ const {
+ showModal,
+ closeHandler,
+ handleChange,
+ doReport,
+ spinning,
+ error
+ } = this.props;
+
+ let spinner = "";
+ if (spinning) {
+ spinner =
+ <Row className="ds-margin-top">
+ <hr />
+ <div className="ds-modal-spinner">
+ <Spinner loading inline size="lg" />Authenticating to all the replicas ...
+ </div>
+ </Row>;
+ }
+
+ return (
+ <Modal show={showModal} onHide={closeHandler}>
+ <div className="ds-no-horizontal-scrollbar">
+ <Modal.Header>
+ <button
+ className="close"
+ onClick={closeHandler}
+ aria-hidden="true"
+ aria-label="Close"
+ >
+ <Icon type="pf" name="close" />
+ </button>
+ <Modal.Title>
+ Replication Login Credentials
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form horizontal autoComplete="off">
+ <p>
+ In order to get the replication agreement lag times and state the
+ authentication credentials to the remote replicas must be provided.
+ This only works if the bind credentials used are valid on all the
+ replicas.
+ </p>
+ <hr />
+ <Row>
+ <Col sm={3}>
+ <ControlLabel>
+ Bind DN
+ </ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <input
+ className={error.binddn ? "ds-input-auto-bad" : "ds-input-auto"}
+ onChange={handleChange} defaultValue="cn=Directory Manager"
+ type="text" id="binddn"
+ />
+ </Col>
+ </Row>
+ <p />
+ <Row>
+ <Col sm={3}>
+ <ControlLabel>
+ Password
+ </ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <input
+ className={error.bindpw ? "ds-input-auto-bad" : "ds-input-auto"}
+ onChange={handleChange} type="password" id="bindpw"
+ />
+ </Col>
+ </Row>
+ {spinner}
+ </Form>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="default"
+ className="btn-cancel"
+ onClick={closeHandler}
+ >
+ Close
+ </Button>
+ <Button
+ bsStyle="primary"
+ onClick={doReport}
+ >
+ Get Report
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ );
+ }
+}
+
+class ReplLagReportModal extends React.Component {
+ render() {
+ const {
+ showModal,
+ closeHandler,
+ agmts,
+ pokeAgmt,
+ viewAgmt
+ } = this.props;
+
+ return (
+ <Modal backdrop="static" contentClassName="ds-lag-report" show={showModal} onHide={closeHandler}>
+ <Modal.Header>
+ <button
+ className="close"
+ onClick={closeHandler}
+ aria-hidden="true"
+ aria-label="Close"
+ >
+ <Icon type="pf" name="close" />
+ </button>
+ <Modal.Title>
+ Replication Lag Report
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <LagReportTable
+ agmts={agmts}
+ pokeAgmt={pokeAgmt}
+ viewAgmt={viewAgmt}
+ />
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="default"
+ className="btn-cancel"
+ onClick={closeHandler}
+ >
+ Close
+ </Button>
+ </Modal.Footer>
+ </Modal>
+ );
+ }
+}
+
+class TaskLogModal extends React.Component {
+ render() {
+ const {
+ showModal,
+ closeHandler,
+ logData,
+ } = this.props;
+
+ return (
+ <Modal show={showModal} onHide={closeHandler}>
+ <div className="ds-no-horizontal-scrollbar">
+ <Modal.Header>
+ <button
+ className="close"
+ onClick={closeHandler}
+ aria-hidden="true"
+ aria-label="Close"
+ >
+ <Icon type="pf" name="close" />
+ </button>
+ <Modal.Title>
+ Task Log
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form horizontal autoComplete="off">
+ <div>
+ <textarea className="ds-logarea" value={logData} readOnly />
+ </div>
+ </Form>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="default"
+ className="btn-cancel"
+ onClick={closeHandler}
+ >
+ Close
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ );
+ }
+}
+
+class AgmtDetailsModal extends React.Component {
+ render() {
+ const {
+ showModal,
+ closeHandler,
+ agmt,
+ } = this.props;
+
+ // Format status dates from agmt
+ let convertedDate = {};
+ let dateAttrs = ['last-update-start', 'last-update-end',
+ 'last-init-start', 'last-init-end'];
+ for (let attr of dateAttrs) {
+ if (agmt[attr] == "19700101000000Z") {
+ convertedDate[attr] = "Unavailable";
+ } else {
+ convertedDate[attr] = get_date_string(agmt[attr]);
+ }
+ }
+
+ return (
+ <Modal show={showModal} onHide={closeHandler}>
+ <div className="ds-no-horizontal-scrollbar">
+ <Modal.Header>
+ <button
+ className="close"
+ onClick={closeHandler}
+ aria-hidden="true"
+ aria-label="Close"
+ >
+ <Icon type="pf" name="close" />
+ </button>
+ <Modal.Title>
+ Replication Agreement Details ({agmt['agmt-name']})
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form horizontal>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Replica</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['replica']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Agreement Enabled</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['replica-enabled']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Init Started</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={convertedDate['last-init-start']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Init Ended</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={convertedDate['last-init-end']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Initialization Status</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <textarea value={agmt['last-init-status']} rows="5" className="ds-agmt-textarea" readOnly />
+ </Col>
+ </Row>
+
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Replication In Progress</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['update-in-progress']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Changes Sent</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['number-changes-sent']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Update Started</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={convertedDate['last-update-start']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Update Ended</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={convertedDate['last-update-end']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Update Status</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <textarea value={agmt['last-update-status']} rows="5" className="ds-agmt-textarea" readOnly />
+ </Col>
+ </Row>
+ </Form>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="default"
+ className="btn-primary ds-float-left"
+ onClick={this.props.initAgmt}
+ >
+ Initialize Agreement
+ </Button>
+ <Button
+ bsStyle="default"
+ className="btn-cancel"
+ onClick={closeHandler}
+ >
+ Close
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ );
+ }
+}
+
+class WinsyncAgmtDetailsModal extends React.Component {
+ render() {
+ const {
+ showModal,
+ closeHandler,
+ agmt,
+ } = this.props;
+
+ // Format status dates from agmt
+ let dateAttrs = ['last-update-start', 'last-update-end',
+ 'last-init-start', 'last-init-end'];
+ for (let attr of dateAttrs) {
+ if (agmt[attr] == "19700101000000Z") {
+ agmt[attr] = "Unavailable";
+ } else {
+ agmt[attr] = get_date_string(agmt[attr]);
+ }
+ }
+
+ return (
+ <Modal show={showModal} onHide={closeHandler}>
+ <div className="ds-no-horizontal-scrollbar">
+ <Modal.Header>
+ <button
+ className="close"
+ onClick={closeHandler}
+ aria-hidden="true"
+ aria-label="Close"
+ >
+ <Icon type="pf" name="close" />
+ </button>
+ <Modal.Title>
+ Replication Winsync Agreement Details ({agmt['agmt-name']})
+ </Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Form horizontal>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Windows Replica</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['replica']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Agreement Enabled</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['replica-enabled']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Init Started</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['last-init-start']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Init Ended</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['last-init-end']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Initialization Status</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <textarea value={agmt['last-init-status']} rows="5" className="ds-agmt-textarea" readOnly />
+ </Col>
+ </Row>
+
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Replication In Progress</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['update-in-progress']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Changes Sent</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['number-changes-sent']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Update Started</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['last-update-start']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Update Ended</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <input className="ds-input-auto" type="text" size="22" value={agmt['last-update-end']} readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={4}>
+ <ControlLabel>Last Update Status</ControlLabel>
+ </Col>
+ <Col sm={8}>
+ <textarea value={agmt['last-update-status']} rows="5" className="ds-agmt-textarea" readOnly />
+ </Col>
+ </Row>
+ </Form>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="default"
+ className="btn-primary ds-float-left"
+ onClick={this.props.initAgmt}
+ >
+ Initialize Agreement
+ </Button>
+ <Button
+ bsStyle="default"
+ className="btn-cancel"
+ onClick={closeHandler}
+ >
+ Close
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ );
+ }
+}
+
+// Prototypes and defaultProps
+AgmtDetailsModal.propTypes = {
+ showModal: PropTypes.bool,
+ closeHandler: PropTypes.func,
+ agmt: PropTypes.object,
+ initAgmt: PropTypes.func,
+};
+
+AgmtDetailsModal.defaultProps = {
+ showModal: false,
+ closeHandler: noop,
+ agmt: {},
+ initAgmt: noop,
+};
+
+WinsyncAgmtDetailsModal.propTypes = {
+ showModal: PropTypes.bool,
+ closeHandler: PropTypes.func,
+ agmt: PropTypes.object,
+ initAgmt: PropTypes.func,
+};
+
+WinsyncAgmtDetailsModal.defaultProps = {
+ showModal: false,
+ closeHandler: noop,
+ agmt: {},
+ initAgmt: noop,
+};
+
+TaskLogModal.propTypes = {
+ showModal: PropTypes.bool,
+ closeHandler: PropTypes.func,
+ logData: PropTypes.string
+};
+
+TaskLogModal.defaultProps = {
+ showModal: false,
+ closeHandler: noop,
+ agreement: "",
+};
+
+ReplLoginModal.propTypes = {
+ showModal: PropTypes.bool,
+ closeHandler: PropTypes.func,
+ handleChange: PropTypes.func,
+ doReport: PropTypes.func,
+ spinning: PropTypes.bool,
+ error: PropTypes.object,
+};
+
+ReplLoginModal.defaultProps = {
+ showModal: false,
+ closeHandler: noop,
+ handleChange: noop,
+ doReport: noop,
+ spinning: false,
+ error: {},
+};
+
+export {
+ TaskLogModal,
+ AgmtDetailsModal,
+ ReplLagReportModal,
+ ReplLoginModal,
+ WinsyncAgmtDetailsModal,
+};
diff --git a/src/cockpit/389-console/src/lib/monitor/monitorTables.jsx b/src/cockpit/389-console/src/lib/monitor/monitorTables.jsx
new file mode 100644
index 0000000..592e514
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/monitorTables.jsx
@@ -0,0 +1,1295 @@
+import React from "react";
+import {
+ Button,
+ DropdownButton,
+ MenuItem,
+ actionHeaderCellFormatter,
+ sortableHeaderCellFormatter,
+ tableCellFormatter,
+ noop
+} from "patternfly-react";
+import { DSTable } from "../dsTable.jsx";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import { get_date_string } from "../tools.jsx";
+
+class AbortCleanALLRUVTable extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ rowKey: "name",
+ columns: [
+ {
+ property: "name",
+ header: {
+ label: "Task Name",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "created",
+ header: {
+ label: "Created",
+ props: {
+ index: 1,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 1
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "rid",
+ header: {
+ label: "Replica ID",
+ props: {
+ index: 2,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 2
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "status",
+ header: {
+ label: "Status",
+ props: {
+ index: 3,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 3
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "log",
+ header: {
+ props: {
+ index: 4,
+ rowSpan: 1,
+ colSpan: 1
+ },
+ formatters: [actionHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 4
+ },
+ formatters: [
+ (value, { rowData }) => {
+ return [
+ <td key={rowData.name[0]}>
+ <Button
+ onClick={() => {
+ this.props.viewLog(this.props.viewLog(rowData.name));
+ }}
+ >
+ View Log
+ </Button>
+ </td>
+ ];
+ }
+ ]
+ }
+ }
+ ],
+ };
+
+ this.getColumns = this.getColumns.bind(this);
+ this.getSingleColumn = this.getSingleColumn.bind(this);
+ } // Constructor
+
+ getColumns() {
+ return this.state.columns;
+ }
+
+ getSingleColumn () {
+ return [
+ {
+ property: "msg",
+ header: {
+ label: "Abort CleanAllRUV Tasks",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ ];
+ }
+
+ render() {
+ let rows = [];
+ for (let task of this.props.tasks) {
+ rows.push({
+ 'name': task.cn,
+ 'created': get_date_string(task.nstaskcreated),
+ 'rid': task['replica-id'],
+ 'status': task.nstaskstatus,
+ });
+ }
+ let taskTable;
+ if (rows.length < 1) {
+ taskTable =
+ <DSTable
+ noSearchBar
+ getColumns={this.getSingleColumn}
+ rowKey={"msg"}
+ rows={[{msg: "No Tasks"}]}
+ />;
+ } else {
+ taskTable =
+ <DSTable
+ noSearchBar
+ getColumns={this.getColumns}
+ rowKey={this.state.rowKey}
+ rows={rows}
+ toolBarPagination={[6, 12, 24, 48, 96]}
+ toolBarPaginationPerPage={6}
+ />;
+ }
+
+ return (
+ <div className="ds-margin-top-xlg">
+ {taskTable}
+ </div>
+ );
+ }
+}
+
+class CleanALLRUVTable extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ rowKey: "name",
+ columns: [
+ {
+ property: "name",
+ header: {
+ label: "Task Name",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "created",
+ header: {
+ label: "Created",
+ props: {
+ index: 1,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 1
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "rid",
+ header: {
+ label: "Replica ID",
+ props: {
+ index: 2,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 2
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "status",
+ header: {
+ label: "Status",
+ props: {
+ index: 3,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 3
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "log",
+ header: {
+ props: {
+ index: 4,
+ rowSpan: 1,
+ colSpan: 1
+ },
+ formatters: [actionHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 4
+ },
+ formatters: [
+ (value, { rowData }) => {
+ return [
+ <td key={rowData.name[0]}>
+ <Button
+ onClick={() => {
+ this.props.viewLog(rowData.name);
+ }}
+ >
+ View Log
+ </Button>
+ </td>
+ ];
+ }
+ ]
+ }
+ }
+ ],
+ };
+
+ this.getColumns = this.getColumns.bind(this);
+ this.getSingleColumn = this.getSingleColumn.bind(this);
+ } // Constructor
+
+ getColumns() {
+ return this.state.columns;
+ }
+
+ getSingleColumn () {
+ return [
+ {
+ property: "msg",
+ header: {
+ label: "CleanAllRUV Tasks",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ ];
+ }
+
+ render() {
+ let rows = [];
+ for (let task of this.props.tasks) {
+ // task.attrs.nstaskcreated[0]
+ rows.push({
+ 'name': task.attrs.cn[0],
+ 'created': get_date_string(task.attrs.nstaskcreated[0]),
+ 'rid': task.attrs['replica-id'][0],
+ 'status': task.attrs.nstaskstatus[0],
+ });
+ }
+
+ let taskTable;
+ if (rows.length < 1) {
+ taskTable =
+ <DSTable
+ noSearchBar
+ getColumns={this.getSingleColumn}
+ rowKey={"msg"}
+ rows={[{msg: "No Tasks"}]}
+ />;
+ } else {
+ taskTable =
+ <DSTable
+ noSearchBar
+ getColumns={this.getColumns}
+ rowKey={this.state.rowKey}
+ rows={rows}
+ toolBarPagination={[6, 12, 24, 48, 96]}
+ toolBarPaginationPerPage={6}
+ />;
+ }
+ return (
+ <div className="ds-margin-top-xlg">
+ {taskTable}
+ </div>
+ );
+ }
+}
+
+class WinsyncAgmtTable extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ fieldsToSearch: ["agmt-name", "replica", "replica-enabled"],
+ rowKey: "agmt-name",
+ columns: [
+ {
+ property: "agmt-name",
+ header: {
+ label: "Agreement",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "replica",
+ header: {
+ label: "Windows Replica",
+ props: {
+ index: 1,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 1
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "replica-enabled",
+ header: {
+ label: "Enabled",
+ props: {
+ index: 2,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 2
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "last-update-status",
+ header: {
+ label: "Update Status",
+ props: {
+ index: 3,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 3
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "number-changes-sent",
+ header: {
+ label: "Changes Sent",
+ props: {
+ index: 4,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 4
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "actions",
+ header: {
+ props: {
+ index: 5,
+ rowSpan: 1,
+ colSpan: 1
+ },
+ formatters: [actionHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 5
+ },
+ formatters: [
+ (value, { rowData }) => {
+ return [
+ <td key={rowData['agmt-name']}>
+ <DropdownButton id={rowData['agmt-name']}
+ bsStyle="default" title="Actions">
+ <MenuItem eventKey="1" onClick={() => {
+ this.props.viewAgmt(rowData['agmt-name']);
+ }}>
+ View Agreement Details
+ </MenuItem>
+ <MenuItem eventKey="2" onClick={() => {
+ this.props.pokeAgmt(rowData['agmt-name']);
+ }}>
+ Poke Agreement
+ </MenuItem>
+ </DropdownButton>
+ </td>
+ ];
+ }
+ ]
+ }
+ }
+ ]
+ };
+ this.getColumns = this.getColumns.bind(this);
+ this.getSingleColumn = this.getSingleColumn.bind(this);
+ } // Constructor
+
+ getColumns() {
+ return this.state.columns;
+ }
+
+ getSingleColumn () {
+ return [
+ {
+ property: "msg",
+ header: {
+ label: "Replication Winsync Agreements",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ ];
+ }
+
+ render() {
+ let agmtTable;
+ if (this.props.agmts.length < 1) {
+ agmtTable =
+ <DSTable
+ noSearchBar
+ getColumns={this.getSingleColumn}
+ rowKey={"msg"}
+ rows={[{msg: "No agreements"}]}
+ />;
+ } else {
+ agmtTable =
+ <DSTable
+ getColumns={this.getColumns}
+ fieldsToSearch={this.state.fieldsToSearch}
+ toolBarSearchField={this.state.searchField}
+ rowKey={this.state.rowKey}
+ rows={this.props.agmts}
+ disableLoadingSpinner
+ toolBarPagination={[6, 12, 24, 48, 96]}
+ toolBarPaginationPerPage={6}
+ />;
+ }
+
+ return (
+ <div className="ds-margin-top-xlg">
+ {agmtTable}
+ </div>
+ );
+ }
+}
+
+class AgmtTable extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ fieldsToSearch: ["agmt-name", "replica", "replica-enabled"],
+ rowKey: "agmt-name",
+ columns: [
+ {
+ property: "agmt-name",
+ header: {
+ label: "Agreement",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "replica",
+ header: {
+ label: "Replica",
+ props: {
+ index: 1,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 1
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "replica-enabled",
+ header: {
+ label: "Enabled",
+ props: {
+ index: 2,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 2
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "last-update-status",
+ header: {
+ label: "Update Status",
+ props: {
+ index: 3,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 3
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "number-changes-sent",
+ header: {
+ label: "Changes Sent",
+ props: {
+ index: 4,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 4
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "actions",
+ header: {
+ props: {
+ index: 5,
+ rowSpan: 1,
+ colSpan: 1
+ },
+ formatters: [actionHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 5
+ },
+ formatters: [
+ (value, { rowData }) => {
+ return [
+ <td key={rowData['agmt-name']}>
+ <DropdownButton id={rowData['agmt-name']}
+ bsStyle="default" title="Actions">
+ <MenuItem eventKey="1" onClick={() => {
+ this.props.viewAgmt(rowData['agmt-name']);
+ }}>
+ View Agreement Details
+ </MenuItem>
+ <MenuItem eventKey="2" onClick={() => {
+ this.props.pokeAgmt(rowData['agmt-name']);
+ }}>
+ Poke Agreement
+ </MenuItem>
+ </DropdownButton>
+ </td>
+ ];
+ }
+ ]
+ }
+ }
+ ]
+ };
+ this.getColumns = this.getColumns.bind(this);
+ this.getSingleColumn = this.getSingleColumn.bind(this);
+ } // Constructor
+
+ getColumns() {
+ return this.state.columns;
+ }
+
+ getSingleColumn () {
+ return [
+ {
+ property: "msg",
+ header: {
+ label: "Replication Agreements",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ ];
+ }
+
+ render() {
+ let agmtTable = "";
+ if (this.props.agmts.length < 1) {
+ agmtTable =
+ <DSTable
+ noSearchBar
+ getColumns={this.getSingleColumn}
+ rowKey={"msg"}
+ rows={[{msg: "No agreements"}]}
+ />;
+ } else {
+ agmtTable =
+ <DSTable
+ getColumns={this.getColumns}
+ rowKey={this.state.rowKey}
+ rows={this.props.agmts}
+ toolBarPagination={[6, 12, 24, 48, 96]}
+ toolBarPaginationPerPage={6}
+ />;
+ }
+ return (
+ <div className="ds-margin-top-xlg">
+ {agmtTable}
+ </div>
+ );
+ }
+}
+
+class ConnectionTable extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ rowKey: "connid",
+ columns: [
+ {
+ property: "date",
+ header: {
+ label: "Connection Opened",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "ip",
+ header: {
+ label: "IP Address",
+ props: {
+ index: 1,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 1
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "connid",
+ header: {
+ label: "ID",
+ props: {
+ index: 2,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 2
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "opStarted",
+ header: {
+ label: "Ops Started",
+ props: {
+ index: 3,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 3
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "opCompleted",
+ header: {
+ label: "Ops Finished",
+ props: {
+ index: 4,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 4
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "binddn",
+ header: {
+ label: "Bind DN",
+ props: {
+ index: 5,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 5
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "readwrite",
+ header: {
+ label: "Read/Write",
+ props: {
+ index: 6,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 6
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ ],
+ };
+
+ this.getColumns = this.getColumns.bind(this);
+ } // Constructor
+
+ getColumns() {
+ return this.state.columns;
+ }
+
+ render() {
+ // connection: %s:%s:%s:%s:%s:%s:%s:%s:%s:%s
+ //
+ // parts:
+ // 0 = file descriptor
+ // 1 = connection start date
+ // 2 = ops initiated
+ // 3 = ops completed
+ // 4 = r/w blocked
+ // 5 = bind DN
+ // 6 = connection is currently at max threads (1 = yes, 0 = no)
+ // 7 = number of times connection hit max threads
+ // 8 = number of operations blocked by max threads
+ // 9 = connection ID
+ // 10 = IP address (ip=###################)
+ //
+ // This is too many items to fit in the table, we have to pick and choose
+ // what "we" think are the most useful stats...
+
+ let rows = [];
+ for (let conn of this.props.conns) {
+ let parts = conn.split(':');
+
+ // Process the IP address
+ let ip = parts[10].replace("ip=", "");
+ if (ip == "local") {
+ ip = "LDAPI";
+ }
+ rows.push({
+ 'date': [get_date_string(parts[1])],
+ 'ip': [ip],
+ 'connid': [parts[9]],
+ 'opStarted': [parts[2]],
+ 'opCompleted': [parts[3]],
+ 'binddn': [parts[5]],
+ 'readwrite': [parts[4]]
+ });
+ }
+
+ return (
+ <div className="ds-margin-top-xlg">
+ <DSTable
+ getColumns={this.getColumns}
+ rowKey={this.state.rowKey}
+ rows={rows}
+ toolBarPagination={[6, 12, 24, 48, 96]}
+ toolBarPaginationPerPage={12}
+ />
+ </div>
+ );
+ }
+}
+
+class LagReportTable extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ rowKey: "agmt-name",
+ columns: [
+ {
+ property: "agmt-name",
+ header: {
+ label: "Agreement",
+ props: {
+ index: 0,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 0
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "replica-enabled",
+ header: {
+ label: "Enabled",
+ props: {
+ index: 1,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 1
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "replication-status",
+ header: {
+ label: "State",
+ props: {
+ index: 2,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true,
+ style: {
+ color: 'blue'
+ }
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 2,
+ },
+ formatters: [tableCellFormatter],
+ },
+ },
+ {
+ property: "replication-lag-time",
+ header: {
+ label: "Lag Time",
+ props: {
+ index: 3,
+ rowSpan: 1,
+ colSpan: 1,
+ sort: true,
+ style: {
+ color: 'blue'
+ },
+ },
+ transforms: [],
+ formatters: [],
+ customFormatters: [sortableHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 3
+ },
+ formatters: [tableCellFormatter]
+ }
+ },
+ {
+ property: "actions",
+ header: {
+ props: {
+ index: 4,
+ rowSpan: 1,
+ colSpan: 1
+ },
+ formatters: [actionHeaderCellFormatter]
+ },
+ cell: {
+ props: {
+ index: 4
+ },
+ formatters: [
+ (value, { rowData }) => {
+ return [
+ <td key={rowData['agmt-name']}>
+ <DropdownButton id={rowData['agmt-name']}
+ bsStyle="default" title="Actions">
+ <MenuItem eventKey="1" onClick={() => {
+ this.props.viewAgmt(rowData['agmt-name']);
+ }}>
+ View Agreement Details
+ </MenuItem>
+ <MenuItem eventKey="2" onClick={() => {
+ this.props.pokeAgmt(rowData['agmt-name']);
+ }}>
+ Poke Agreement
+ </MenuItem>
+ </DropdownButton>
+ </td>
+ ];
+ }
+ ]
+ }
+ }
+ ]
+ };
+ this.getColumns = this.getColumns.bind(this);
+ } // Constructor
+
+ getColumns() {
+ return this.state.columns;
+ }
+
+ render() {
+ return (
+ <div>
+ <DSTable
+ noSearchBar
+ getColumns={this.getColumns}
+ rowKey={this.state.rowKey}
+ rows={this.props.agmts}
+ toolBarPagination={[6, 12, 24, 48, 96]}
+ toolBarPaginationPerPage={6}
+ />
+ </div>
+ );
+ }
+}
+
+// Proptypes and defaults
+
+LagReportTable.propTypes = {
+ agmts: PropTypes.array,
+ viewAgmt: PropTypes.func,
+ pokeAgmt: PropTypes.func,
+};
+
+LagReportTable.defaultProps = {
+ agmts: [],
+ viewAgmt: noop,
+ pokeAgmt: noop
+};
+
+AgmtTable.propTypes = {
+ agmts: PropTypes.array,
+ viewAgmt: PropTypes.func,
+ pokeAgmt: PropTypes.func,
+};
+
+AgmtTable.defaultProps = {
+ agmts: [],
+ viewAgmt: noop,
+ pokeAgmt: noop
+};
+
+// Proptyes and defaults
+WinsyncAgmtTable.propTypes = {
+ agmts: PropTypes.array,
+ viewAgmt: PropTypes.func,
+ pokeAgmt: PropTypes.func,
+};
+
+WinsyncAgmtTable.defaultProps = {
+ agmts: [],
+ viewAgmt: noop,
+ pokeAgmt: noop
+};
+
+ConnectionTable.propTypes = {
+ conns: PropTypes.array,
+};
+
+ConnectionTable.defaultProps = {
+ conns: [],
+};
+
+CleanALLRUVTable.propTypes = {
+ tasks: PropTypes.array,
+ viewLog: PropTypes.func,
+};
+
+CleanALLRUVTable.defaultProps = {
+ tasks: [],
+ viewLog: PropTypes.func,
+};
+
+AbortCleanALLRUVTable.propTypes = {
+ tasks: PropTypes.array,
+ viewLog: PropTypes.func,
+};
+
+AbortCleanALLRUVTable.defaultProps = {
+ tasks: [],
+ viewLog: PropTypes.func,
+};
+
+export {
+ ConnectionTable,
+ AgmtTable,
+ WinsyncAgmtTable,
+ LagReportTable,
+ CleanALLRUVTable,
+ AbortCleanALLRUVTable,
+};
diff --git a/src/cockpit/389-console/src/lib/monitor/replMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/replMonitor.jsx
new file mode 100644
index 0000000..a742a0d
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/replMonitor.jsx
@@ -0,0 +1,538 @@
+import React from "react";
+import cockpit from "cockpit";
+import { log_cmd } from "../tools.jsx";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import { ConfirmPopup } from "../notifications.jsx";
+import {
+ AgmtTable,
+ WinsyncAgmtTable,
+ CleanALLRUVTable,
+ AbortCleanALLRUVTable
+} from "./monitorTables.jsx";
+import {
+ TaskLogModal,
+ AgmtDetailsModal,
+ WinsyncAgmtDetailsModal,
+ ReplLagReportModal,
+ ReplLoginModal,
+} from "./monitorModals.jsx";
+import {
+ Nav,
+ NavItem,
+ TabContent,
+ TabPane,
+ TabContainer,
+ Button,
+ noop
+} from "patternfly-react";
+
+export class ReplMonitor extends React.Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ activeKey: 1,
+ logData: "",
+ showBindModal: false,
+ showLogModal: false,
+ showAgmtModal: false,
+ showWinsyncAgmtModal: false,
+ showInitWinsyncConfirm: false,
+ showInitConfirm: false,
+ showLoginModal: false,
+ showLagReport: false,
+ reportLoading: false,
+ lagAgmts: [],
+ agmt: "",
+ binddn: "cn=Directory Manager",
+ bindpw: "",
+ errObj: {}
+ };
+
+ this.handleNavSelect = this.handleNavSelect.bind(this);
+ this.pokeAgmt = this.pokeAgmt.bind(this);
+ this.initAgmt = this.initAgmt.bind(this);
+ this.initWinsyncAgmt = this.initWinsyncAgmt.bind(this);
+ this.confirmInit = this.confirmInit.bind(this);
+ this.confirmWinsyncInit = this.confirmWinsyncInit.bind(this);
+ this.closeInitConfirm = this.closeInitConfirm.bind(this);
+ this.closeInitWinsyncConfirm = this.closeInitWinsyncConfirm.bind(this);
+ this.pokeWinsyncAgmt = this.pokeWinsyncAgmt.bind(this);
+ this.showAgmtModal = this.showAgmtModal.bind(this);
+ this.closeAgmtModal = this.closeAgmtModal.bind(this);
+ this.showWinsyncAgmtModal = this.showWinsyncAgmtModal.bind(this);
+ this.closeWinsyncAgmtModal = this.closeWinsyncAgmtModal.bind(this);
+ this.getLagReportCreds = this.getLagReportCreds.bind(this);
+ this.doLagReport = this.doLagReport.bind(this);
+ this.closeLagReport = this.closeLagReport.bind(this);
+ this.viewCleanLog = this.viewCleanLog.bind(this);
+ this.viewAbortLog = this.viewAbortLog.bind(this);
+ this.closeLogModal = this.closeLogModal.bind(this);
+ this.handleLoginModal = this.handleLoginModal.bind(this);
+ this.closeLoginModal = this.closeLoginModal.bind(this);
+ }
+
+ handleNavSelect(key) {
+ this.setState({
+ activeKey: key
+ });
+ }
+
+ closeLogModal() {
+ this.setState({
+ showLogModal: false
+ });
+ }
+
+ viewCleanLog (name) {
+ let logData = "";
+ for (let task of this.props.data.cleanTasks) {
+ if (task.attrs.cn[0] == name) {
+ logData = task.attrs.nstasklog[0];
+ break;
+ }
+ }
+ this.setState({
+ showLogModal: true,
+ logData: logData
+ });
+ }
+
+ viewAbortLog (name) {
+ let logData = "";
+ for (let task of this.props.data.abortTasks) {
+ if (task.attrs.cn[0] == name) {
+ logData = task.attrs.nstasklog[0];
+ break;
+ }
+ }
+ this.setState({
+ showLogModal: true,
+ logData: logData
+ });
+ }
+
+ pokeAgmt (name) {
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "repl-agmt", "poke", "--suffix=" + this.props.suffix, name];
+ log_cmd("pokeAgmt", "Awaken the agreement", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.props.addNotification(
+ "success",
+ `Replication agreement has been poked`
+ );
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.props.addNotification(
+ "error",
+ `Failed to poke replication agreement ${name} - ${errMsg.desc}`
+ );
+ });
+ }
+
+ pokeWinsyncAgmt(name) {
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "repl-winsync-agmt", "poke", "--suffix=" + this.props.suffix, name];
+ log_cmd("pokeAgmt", "Awaken the agreement", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.props.addNotification(
+ "success",
+ `Replication winsync agreement has been poked`
+ );
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.props.addNotification(
+ "error",
+ `Failed to poke replication winsync agreement ${name} - ${errMsg.desc}`
+ );
+ });
+ }
+
+ showAgmtModal (name) {
+ for (let agmt of this.props.data.replAgmts) {
+ if (agmt['agmt-name'] == name) {
+ this.setState({
+ showAgmtModal: true,
+ agmt: agmt
+ });
+ break;
+ }
+ }
+ }
+
+ closeAgmtModal() {
+ this.setState({
+ showAgmtModal: false,
+ });
+ }
+
+ showWinsyncAgmtModal(name) {
+ for (let agmt of this.props.data.replWinsyncAgmts) {
+ if (agmt['agmt-name'] == name) {
+ this.setState({
+ showWinsyncAgmtModal: true,
+ agmt: agmt
+ });
+ break;
+ }
+ }
+ }
+
+ closeWinsyncAgmtModal() {
+ this.setState({
+ showWinsyncAgmtModal: false,
+ });
+ }
+
+ confirmInit() {
+ this.setState({
+ showInitConfirm: true,
+ });
+ }
+
+ closeInitConfirm() {
+ this.setState({
+ showInitConfirm: false
+ });
+ }
+
+ confirmWinsyncInit() {
+ this.setState({
+ showInitWinsyncConfirm: true
+ });
+ }
+
+ closeInitWinsyncConfirm() {
+ this.setState({
+ showInitWinsyncConfirm: false
+ });
+ }
+
+ initAgmt() {
+ let cmd = ['dsconf', '-j', 'ldapi://%2fvar%2frun%2fslapd-' + this.props.serverId + '.socket',
+ 'repl-agmt', 'init', '--suffix=' + this.props.suffix, this.state.agmt['agmt-name'] ];
+ log_cmd('initAgmt', 'Initialize agreement', cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.props.reloadAgmts();
+ this.props.addNotification(
+ "success",
+ `Replication agreement initialization has started ...`
+ );
+ this.setState({
+ showAgmtModal: false
+ });
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.props.addNotification(
+ "error",
+ `Failed to start agreement initialization - ${errMsg.desc}`
+ );
+ this.setState({
+ showAgmtModal: false
+ });
+ });
+ }
+
+ initWinsyncAgmt() {
+ let cmd = ['dsconf', '-j', 'ldapi://%2fvar%2frun%2fslapd-' + this.props.serverId + '.socket',
+ 'repl-winsync-agmt', 'init', '--suffix=' + this.props.suffix, this.state.agmt['agmt-name'] ];
+ log_cmd('initWinsyncAgmt', 'Initialize winsync agreement', cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.props.reloadWinsyncAgmts();
+ this.props.addNotification(
+ "success",
+ `Replication winsync agreement initialization has started ...`
+ );
+ this.setState({
+ showInitWinsyncConfirm: false
+ });
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.props.addNotification(
+ "error",
+ `Failed to start winsync agreement initialization - ${errMsg.desc}`
+ );
+ this.setState({
+ showInitWinsyncConfirm: false
+ });
+ });
+ }
+
+ getLagReportCreds () {
+ if (this.props.data.replAgmts.length == 0) {
+ // No agreements, don't proceed...
+ this.props.addNotification(
+ "error", "There are no replication agreements to report on"
+ );
+ } else {
+ this.setState({
+ showLoginModal: true,
+ errObj: {
+ bindpw: true
+ }
+ });
+ }
+ }
+
+ closeLoginModal () {
+ this.setState({
+ showLoginModal: false,
+ });
+ }
+
+ handleLoginModal(e) {
+ const value = e.target.value.trim();
+ let valueErr = false;
+ let errObj = this.state.errObj;
+ if (value == "") {
+ valueErr = true;
+ }
+ errObj[e.target.id] = valueErr;
+ this.setState({
+ [e.target.id]: value,
+ errObj: errObj
+ });
+ }
+
+ closeLagReport() {
+ this.setState({
+ showLagReport: false
+ });
+ }
+
+ doLagReport() {
+ // Get agmts but this time with with bind credentials, then clear
+ // out bind credentials after we use them
+
+ if (this.state.binddn == "" || this.state.bindpw == "") {
+ return;
+ }
+
+ this.setState({
+ loginSpinning: true,
+ });
+
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "replication", "status", "--suffix=" + this.props.suffix,
+ "--bind-dn=" + this.state.binddn, "--bind-passwd=" + this.state.bindpw];
+ log_cmd("doLagReport", "Get agmts for lag report", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ lagAgmts: config.items,
+ showLagReport: true,
+ showLoginModal: false,
+ loginSpinning: false,
+ bindpw: ""
+ });
+ })
+ .fail(err => {
+ let errMsg = JSON.parse(err);
+ this.props.addNotification(
+ "error",
+ `Failed to get replication status - ${errMsg.desc}`
+ );
+ this.setState({
+ showLoginModal: false,
+ loginSpinning: false,
+ bindpw: ""
+ });
+ });
+ }
+
+ render() {
+ let replAgmts = this.props.data.replAgmts;
+ let replWinsyncAgmts = this.props.data.replWinsyncAgmts;
+ let cleanTasks = this.props.data.cleanTasks;
+ let abortTasks = this.props.data.abortTasks;
+ let agmtDetailModal = "";
+ let winsyncAgmtDetailModal = "";
+
+ if (this.state.showAgmtModal) {
+ agmtDetailModal =
+ <AgmtDetailsModal
+ showModal={this.state.showAgmtModal}
+ closeHandler={this.closeAgmtModal}
+ agmt={this.state.agmt}
+ initAgmt={this.confirmInit}
+ />;
+ }
+
+ if (this.state.showWinsyncAgmtModal) {
+ winsyncAgmtDetailModal =
+ <WinsyncAgmtDetailsModal
+ showModal={this.state.showWinsyncAgmtModal}
+ closeHandler={this.closeWinsyncAgmtModal}
+ agmt={this.state.agmt}
+ initAgmt={this.confirmWinsyncInit}
+ />;
+ }
+
+ let cleanNavTitle = 'CleanAllRUV Tasks <font size="1">(' + cleanTasks.length + ')</font>';
+ let abortNavTitle = 'Abort CleanAllRUV Tasks <font size="1">(' + abortTasks.length + ')</font>';
+ let taskContent =
+ <div>
+ <Nav bsClass="nav nav-tabs nav-tabs-pf">
+ <NavItem className="ds-nav-med" eventKey={1}>
+ <div dangerouslySetInnerHTML={{__html: cleanNavTitle}} />
+ </NavItem>
+ <NavItem className="ds-nav-med" eventKey={2}>
+ <div dangerouslySetInnerHTML={{__html: abortNavTitle}} />
+ </NavItem>
+ </Nav>
+ <TabContent>
+ <TabPane eventKey={1}>
+ <div className="ds-indent ds-margin-top-lg">
+ <CleanALLRUVTable
+ tasks={cleanTasks}
+ viewLog={this.viewCleanLog}
+ />
+ </div>
+ </TabPane>
+ <TabPane eventKey={2}>
+ <div className="ds-indent ds-margin-top-lg">
+ <AbortCleanALLRUVTable
+ tasks={abortTasks}
+ viewLog={this.viewAbortLog}
+ />
+ </div>
+ </TabPane>
+ </TabContent>
+ </div>;
+
+ let AgmtNavTitle = 'Agreements <font size="1">(' + replAgmts.length + ')</font>';
+ let WinsyncAgmtNavTitle = 'Winsync Agreements <font size="1">(' + replWinsyncAgmts.length + ')</font>';
+ let TasksNavTitle = 'Tasks <font size="1">(' + (cleanTasks.length + abortTasks.length) + ')</font>';
+
+ return (
+ <div id="monitor-suffix-page" className="container-fluid ds-tab-table">
+ <TabContainer id="basic-tabs-pf" onSelect={this.handleNavSelect} activeKey={this.state.activeKey}>
+ <div>
+ <Nav bsClass="nav nav-tabs nav-tabs-pf">
+ <NavItem eventKey={1}>
+ <div dangerouslySetInnerHTML={{__html: AgmtNavTitle}} />
+ </NavItem>
+ <NavItem eventKey={2}>
+ <div dangerouslySetInnerHTML={{__html: WinsyncAgmtNavTitle}} />
+ </NavItem>
+ <NavItem eventKey={3}>
+ <div dangerouslySetInnerHTML={{__html: TasksNavTitle}} />
+ </NavItem>
+ </Nav>
+ <TabContent>
+ <TabPane eventKey={1}>
+ <div className="ds-margin-top-lg">
+ <AgmtTable
+ agmts={replAgmts}
+ pokeAgmt={this.pokeAgmt}
+ viewAgmt={this.showAgmtModal}
+ />
+ <p />
+ <Button
+ bsStyle="primary"
+ onClick={this.getLagReportCreds}
+ title="Display report that shows the lag time and replication status of each agreement in relationship to its replica"
+ >
+ Get Lag Report
+ </Button>
+ </div>
+ </TabPane>
+
+ <TabPane eventKey={2}>
+ <div className="ds-margin-top-lg">
+ <WinsyncAgmtTable
+ agmts={replWinsyncAgmts}
+ pokeAgmt={this.pokeWinsyncAgmt}
+ viewAgmt={this.showWinsyncAgmtModal}
+ />
+ </div>
+ </TabPane>
+
+ <TabPane eventKey={3}>
+ <div className="ds-indent ds-tab-table">
+ <TabContainer id="task-tabs" defaultActiveKey={1}>
+ {taskContent}
+ </TabContainer>
+ </div>
+ </TabPane>
+ </TabContent>
+ </div>
+ </TabContainer>
+ <TaskLogModal
+ showModal={this.state.showLogModal}
+ closeHandler={this.closeLogModal}
+ logData={this.state.logData}
+ />
+ <ConfirmPopup
+ showModal={this.state.showInitConfirm}
+ closeHandler={this.closeInitConfirm}
+ actionFunc={this.initAgmt}
+ actionParam={this.state.agmt['agmt-name']}
+ msg="Are you really sure you want to reinitialize this replication agreement?"
+ msgContent={this.state.agmt['agmt-name']}
+ />
+ <ConfirmPopup
+ showModal={this.state.showInitWinsyncConfirm}
+ closeHandler={this.closeInitWinsyncConfirm}
+ actionFunc={this.initWinsyncAgmt}
+ actionParam={this.state.agmt['agmt-name']}
+ msg="Are you really sure you want to reinitialize this replication winsync agreement?"
+ msgContent={this.state.agmt['agmt-name']}
+ />
+ <ReplLoginModal
+ showModal={this.state.showLoginModal}
+ closeHandler={this.closeLoginModal}
+ handleChange={this.handleLoginModal}
+ doReport={this.doLagReport}
+ spinning={this.state.loginSpinning}
+ error={this.state.errObj}
+ />
+ <ReplLagReportModal
+ showModal={this.state.showLagReport}
+ closeHandler={this.closeLagReport}
+ agmts={this.state.lagAgmts}
+ pokeAgmt={this.pokeAgmt}
+ viewAgmt={this.showAgmtModal}
+ />
+ {agmtDetailModal}
+ {winsyncAgmtDetailModal}
+ </div>
+ );
+ }
+}
+
+// Props and defaultProps
+
+ReplMonitor.propTypes = {
+ data: PropTypes.object,
+ suffix: PropTypes.string,
+ serverId: PropTypes.string,
+ addNotification: PropTypes.func,
+ reloadAgmts: PropTypes.func,
+ reloadWinsyncAgmts: PropTypes.func,
+};
+
+ReplMonitor.defaultProps = {
+ data: {},
+ suffix: "",
+ serverId: "",
+ addNotification: noop,
+ reloadAgmts: noop,
+ reloadWinsyncAgmts: noop,
+};
+
+export default ReplMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
new file mode 100644
index 0000000..503b57d
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/serverMonitor.jsx
@@ -0,0 +1,161 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import { get_date_string, get_date_diff } from "../tools.jsx";
+import {
+ ConnectionTable
+} from "./monitorTables.jsx";
+import {
+ Nav,
+ NavItem,
+ TabContent,
+ TabPane,
+ TabContainer,
+ Row,
+ Col,
+ ControlLabel,
+ Icon,
+ noop
+} from "patternfly-react";
+
+export class ServerMonitor extends React.Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ activeKey: 1,
+ };
+ this.handleNavSelect = this.handleNavSelect.bind(this);
+ }
+
+ handleNavSelect(key) {
+ this.setState({ activeKey: key });
+ }
+
+ render() {
+ // Generate start time and Uptime
+ let startTime = this.props.data.starttime[0];
+ let currTime = this.props.data.currenttime[0];
+ let startDate = get_date_string(this.props.data.starttime[0]);
+ let uptime = get_date_diff(startTime, currTime);
+
+ return (
+ <div id="monitor-server-page" className="container-fluid">
+ <Row>
+ <Col sm={12} className="ds-word-wrap">
+ <ControlLabel className="ds-suffix-header">
+ Server Statistics
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh server monitor"
+ onClick={this.props.reload}
+ />
+ </ControlLabel>
+ </Col>
+ </Row>
+
+ <TabContainer id="server-tabs-pf" onSelect={this.handleNavSelect} activeKey={this.state.activeKey}>
+ <div>
+ <Nav bsClass="nav nav-tabs nav-tabs-pf">
+ <NavItem eventKey={1}>
+ <div dangerouslySetInnerHTML={{__html: 'Server Information'}} />
+ </NavItem>
+ <NavItem eventKey={2}>
+ <div dangerouslySetInnerHTML={{__html: 'Connection Table'}} />
+ </NavItem>
+ </Nav>
+ <TabContent>
+
+ <TabPane eventKey={1}>
+ <div className="ds-container ds-margin-top-lg">
+ <div className="ds-inline">
+ <div>
+ <label htmlFor="monitor-serverid" className="ds-label-xsm">Server Instance</label><input type="text"
+ className="ds-input" id="monitor-serverid" value={"slapd-" + this.props.serverId} size="50" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-version" className="ds-label-xsm">Version</label><input type="text"
+ className="ds-input" id="monitor-version" value={this.props.data.version} size="50" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-starttime" className="ds-label-xsm">Server Started</label><input type="text"
+ className="ds-input" id="monitor-server-starttime" value={startDate} size="50" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-uptime" className="ds-label-xsm">Server Uptime</label><input type="text"
+ className="ds-input" id="monitor-server-uptime" value={uptime} size="50" readOnly />
+ </div>
+ </div>
+ </div>
+ <hr />
+ <div className="ds-container">
+ <div className="ds-inline">
+ <div>
+ <label htmlFor="monitor-server-threads" className="ds-monitor-label">Threads</label><input type="text"
+ className="ds-input" id="monitor-server-threads" value={this.props.data.threads} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-totalconnections" className="ds-monitor-label">Total Connections</label><input type="text"
+ className="ds-input" id="monitor-server-totalconnections" value={this.props.data.totalconnections} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-currentconnections" className="ds-monitor-label">Current Conections</label><input type="text"
+ className="ds-input" id="monitor-server-currentconnections" value={this.props.data.currentconnections} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-currentconnectionsatmaxthreads" className="ds-monitor-label">Conns At Max Threads</label><input type="text"
+ className="ds-input" id="monitor-server-currentconnectionsatmaxthreads" value={this.props.data.currentconnectionsatmaxthreads} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-maxthreadsperconnhits" className="ds-monitor-label">Conns Hit Max Threads</label><input type="text"
+ className="ds-input" id="monitor-server-maxthreadsperconnhits" value={this.props.data.maxthreadsperconnhits} size="12" readOnly />
+ </div>
+ </div>
+ <div className="ds-divider" />
+ <div className="ds-inline">
+ <div>
+ <label htmlFor="monitor-server-readwaiters" className="ds-monitor-label-med">Threads Waiting To Read</label><input type="text"
+ className="ds-input" id="monitor-server-readwaiters" value={this.props.data.readwaiters} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-opsinitiated" className="ds-monitor-label-med">Operations Started</label><input type="text"
+ className="ds-input" id="monitor-server-opsinitiated" value={this.props.data.opsinitiated} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-opscompleted" className="ds-monitor-label-med">Operations Completed</label><input type="text"
+ className="ds-input" id="monitor-server-opscompleted" value={this.props.data.opscompleted} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-entriessent" className="ds-monitor-label-med">Entries Returned To Clients</label><input type="text"
+ className="ds-input" id="monitor-server-entriessent" value={this.props.data.entriessent} size="12" readOnly />
+ </div>
+ <div>
+ <label htmlFor="monitor-server-bytessent" className="ds-monitor-label-med">Bytes Sent to Clients</label><input type="text"
+ className="ds-input" id="monitor-server-bytessent" value={this.props.data.bytessent} size="12" readOnly />
+ </div>
+
+ </div>
+ </div>
+ </TabPane>
+ <TabPane eventKey={2}>
+ <ConnectionTable conns={this.props.data.connection} />
+ </TabPane>
+ </TabContent>
+ </div>
+ </TabContainer>
+ </div>
+ );
+ }
+}
+
+ServerMonitor.propTypes = {
+ serverId: PropTypes.string,
+ data: PropTypes.object,
+ reload: PropTypes.func
+};
+
+ServerMonitor.defaultProps = {
+ serverId: "",
+ data: {},
+ reload: noop
+};
+
+export default ServerMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/snmpMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/snmpMonitor.jsx
new file mode 100644
index 0000000..fd1a4f1
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/snmpMonitor.jsx
@@ -0,0 +1,223 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ Row,
+ Col,
+ Icon,
+ ControlLabel,
+ noop
+} from "patternfly-react";
+
+export class SNMPMonitor extends React.Component {
+ render() {
+ return (
+ <div className="container-fluid" id="db-global-page">
+ <Row>
+ <Col sm={12} className="ds-word-wrap">
+ <ControlLabel className="ds-suffix-header">
+ SNMP Counters
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh SNMP monitor"
+ onClick={this.props.reload}
+ />
+ </ControlLabel>
+ </Col>
+ </Row>
+ <div className="ds-margin-top-med">
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Anonymous Binds</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.anonymousbinds} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Referrals</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.referrals} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Unauthenticated Binds</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.anonymousbinds} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Returned Referrals</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.referralsreturned} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Simple Auth Binds</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.simpleauthbinds} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Bind Security Errors</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.bindsecurityerrors} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Strong Auth Binds</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.strongauthbinds} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Security Errors</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.securityerrors} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Initiated Operations</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.inops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Errors</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.errors} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Compare Operations</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.compareops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Current Connections</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.connections} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Add Operations</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.addentryops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Total Connections</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.connectionseq} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Delete Operations</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.removeentryops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Conns in Max Threads</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.connectionsinmaxthreads} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Modify Operation</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.modifyentryops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Conns Hit Max Threads</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.connectionsmaxthreadscount} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>ModRDN Operations</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.modifyrdnops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Bytes Received</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.bytesrecv} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Search Operations</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.searchops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Bytes Sent</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.bytessent} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>One Level Searches</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.onelevelsearchops} size="10" readOnly />
+ </Col>
+ <Col sm={3}>
+ <ControlLabel>Entries Sent</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.entriesreturned} size="10" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>Whole Tree Searches</ControlLabel>
+ </Col>
+ <Col sm={2}>
+ <input type="text" value={this.props.data.wholesubtreesearchops} size="10" readOnly />
+ </Col>
+
+ </Row>
+ </div>
+ </div>
+ );
+ }
+}
+
+// Prop types and defaults
+
+SNMPMonitor.propTypes = {
+ data: PropTypes.object,
+ reload: PropTypes.func
+};
+
+SNMPMonitor.defaultProps = {
+ data: {},
+ reload: noop
+};
+
+export default SNMPMonitor;
diff --git a/src/cockpit/389-console/src/lib/monitor/suffixMonitor.jsx b/src/cockpit/389-console/src/lib/monitor/suffixMonitor.jsx
new file mode 100644
index 0000000..f859f57
--- /dev/null
+++ b/src/cockpit/389-console/src/lib/monitor/suffixMonitor.jsx
@@ -0,0 +1,423 @@
+import React from "react";
+import PropTypes from "prop-types";
+import "../../css/ds.css";
+import {
+ DonutChart,
+ PieChart,
+ ControlLabel,
+ Row,
+ Col,
+ Icon,
+ Nav,
+ NavItem,
+ TabContent,
+ TabPane,
+ TabContainer,
+ noop
+} from "patternfly-react";
+import d3 from "d3";
+
+export class SuffixMonitor extends React.Component {
+ constructor (props) {
+ super(props);
+ this.state = {
+ activeKey: 1,
+ };
+ this.handleNavSelect = this.handleNavSelect.bind(this);
+ }
+
+ handleNavSelect(key) {
+ this.setState({ activeKey: key });
+ }
+
+ render() {
+ let badColor = "#d01c8b";
+ let warningColor = "#ffc107";
+ let goodColor = "#4dac26";
+ let emptyColor = "#d3d3d3";
+ let donutColorEC = goodColor;
+ let donutColorECMiss = emptyColor;
+ let donutColorECUtil = goodColor;
+ let donutColorDN = goodColor;
+ let donutColorDNMiss = emptyColor;
+ let donutColorDNUtil = goodColor;
+
+ // Entry cache
+ let cachehit = parseInt(this.props.data.entrycachehitratio[0]);
+ let cachemax = parseInt(this.props.data.maxentrycachesize[0]);
+ let cachecurr = parseInt(this.props.data.currententrycachesize[0]);
+ let cachecount = parseInt(this.props.data.currententrycachecount[0]);
+ let utilratio = Math.round((cachecurr / cachemax) * 100);
+ // DN cache
+ let dncachehit = parseInt(this.props.data.dncachehitratio[0]);
+ let dncachemax = parseInt(this.props.data.maxdncachesize[0]);
+ let dncachecurr = parseInt(this.props.data.currentdncachesize[0]);
+ let dncachecount = parseInt(this.props.data.currentdncachecount[0]);
+ let dnutilratio = Math.round((dncachecurr / dncachemax) * 100);
+
+ // Adjust ratios if needed
+ if (utilratio == 0) {
+ utilratio = 1;
+ }
+ if (dnutilratio == 0) {
+ dnutilratio = 1;
+ }
+
+ // Entry Cache
+ if (cachehit > 89) {
+ donutColorEC = goodColor;
+ } else if (cachehit > 74) {
+ donutColorEC = warningColor;
+ } else {
+ if (cachehit < 50) {
+ // Pie chart shows higher catagory, so we need to highlight the misses
+ donutColorECMiss = badColor;
+ } else {
+ donutColorEC = badColor;
+ }
+ }
+ // Entry cache utilization
+ if (cachehit < 90) {
+ if (utilratio > 95) {
+ donutColorECUtil = badColor;
+ } else if (utilratio > 90) {
+ donutColorECUtil = warningColor;
+ }
+ }
+ // DN cache ratio
+ if (dncachehit > 89) {
+ donutColorDN = goodColor;
+ } else if (dncachehit > 74) {
+ donutColorDN = warningColor;
+ } else {
+ if (dncachehit < 50) {
+ // Pie chart shows higher catagory, so we need to highlight the misses
+ donutColorDNMiss = badColor;
+ } else {
+ donutColorDN = badColor;
+ }
+ }
+ // DN cache utilization
+ if (dncachehit < 90) {
+ if (dnutilratio > 95) {
+ donutColorDNUtil = badColor;
+ } else if (dnutilratio > 90) {
+ donutColorDNUtil = warningColor;
+ }
+ }
+
+ let suffixIcon = "tree";
+ if (this.props.dbtype == "subsuffix") {
+ suffixIcon = "leaf";
+ }
+
+ return (
+ <div id="monitor-suffix-page" className="container-fluid">
+ <Row>
+ <Col sm={12} className="ds-word-wrap">
+ <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 monitor"
+ onClick={() => this.props.reload(this.props.suffix)}
+ />
+ </ControlLabel>
+ </Col>
+ </Row>
+ <p />
+ <TabContainer id="basic-tabs-pf" onSelect={this.handleNavSelect} activeKey={this.state.activeKey}>
+ <div>
+ <Nav bsClass="nav nav-tabs nav-tabs-pf">
+ <NavItem eventKey={1}>
+ <div dangerouslySetInnerHTML={{__html: 'Entry Cache'}} />
+ </NavItem>
+ <NavItem eventKey={2}>
+ <div dangerouslySetInnerHTML={{__html: 'DN Cache'}} />
+ </NavItem>
+ </Nav>
+ <TabContent>
+
+ <TabPane eventKey={1}>
+ <div className="ds-margin-top-lg">
+ <div className="ds-container">
+ <div className="ds-divider" />
+ <div className="ds-left-margin" title="The entry cache hit ratio. If the chart is RED then the hit ratio is below 90% and might require further cache tuning">
+ <DonutChart
+ id="monitor-entry-cache-pie"
+ size={{width: 180, height: 120}}
+ data={{
+ columns: [['miss', 100 - cachehit], ['hit', cachehit]],
+ colors: {
+ 'hit': donutColorEC,
+ 'miss': donutColorECMiss,
+ },
+ order: null,
+ unload: true
+ }}
+ title={{type: 'percent'}}
+ legend={{show: true, position: 'right'}}
+ />
+ <b>Entry Cache Hit Ratio</b>
+ </div>
+ <div className="ds-chart-right" title="How much of the allocated cache space is used (max size vs current size). If the chart is RED then you should to increase the max cache size because the cache hit ratio is below 90%">
+ <PieChart
+ id="monitor-entry-util-pie"
+ size={{width: 180, height: 120}}
+ data={{
+ columns: [
+ ['Used', utilratio],
+ ['Unused', 100 - utilratio],
+ ],
+ colors: {
+ 'Used': donutColorECUtil,
+ 'Unused': emptyColor,
+ },
+ order: null,
+ type: 'pie'
+ }}
+ pie={{
+ label: {
+ format: function (value, ratio, id) {
+ return d3.format(',%')(value / 100);
+ }
+ }
+ }}
+ title={{type: 'pie'}}
+ legend={{show: true, position: 'right'}}
+ />
+ <b>Entry Cache Utilization</b>
+ <div>
+ (Entries in cache: <b>{cachecount}</b>)
+ </div>
+ </div>
+ </div>
+ <p />
+ <hr />
+ <div>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Entry Cache Hit Ratio
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.entrycachehitratio} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Entry Cache Tries
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.entrycachetries} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Entry Cache Hits
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.entrycachehits} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Entry Cache Max Size
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.maxentrycachesize} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Entry Cache Current Size
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.currententrycachesize} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Entry Cache Max Entries
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.maxentrycachecount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ Entry Cache Count
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.currententrycachecount} size="35" readOnly />
+ </Col>
+ </Row>
+ </div>
+ </div>
+ </TabPane>
+
+ <TabPane eventKey={2}>
+ <div className="ds-margin-top-lg">
+ <div className="ds-container">
+ <div className="ds-divider" />
+ <div className="ds-left-margin" title="The DN cache hit ratio. If the chart is RED then the hit ratio is below 90% and might require further cache tuning">
+ <DonutChart
+ id="monitor-entry-cache-pie"
+ size={{width: 180, height: 120}}
+ data={{
+ columns: [['miss', 100 - dncachehit], ['hit', dncachehit]],
+ colors: {
+ 'hit': donutColorDN,
+ 'miss': donutColorDNMiss,
+ },
+ order: null,
+ }}
+ title={{type: 'percent'}}
+ legend={{show: true, position: 'right'}}
+ />
+ <b className="ds-left-margin">DN Cache Hit Ratio</b>
+ </div>
+ <div className="ds-chart-right" title="How much of the allocated cache space is used (max size vs current size). If the chart is RED then you should to increase the max cache size because the cache hit ratio is below 90%">
+ <PieChart
+ id="monitor-entry-util-pie"
+ size={{width: 180, height: 120}}
+ data={{
+ columns: [
+ ['Used', dnutilratio],
+ ['Unused', 100 - dnutilratio],
+ ],
+ colors: {
+ 'Used': donutColorDNUtil,
+ 'Unused': emptyColor,
+ },
+ order: null,
+ type: 'pie'
+ }}
+ pie={{
+ label: {
+ format: function (value, ratio, id) {
+ return d3.format(',%')(value / 100);
+ }
+ }
+ }}
+ title={{type: 'pie'}}
+ legend={{show: true, position: 'right'}}
+ />
+ <div className="ds-left-margin">
+ <b>DN Cache Utilization</b>
+ <div>
+ (DN's in cache: <b>{dncachecount}</b>)
+ </div>
+ </div>
+ </div>
+ </div>
+ <hr />
+ <div>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ DN Cache Hit Ratio
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dncachehitratio} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ DN Cache Tries
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dncachetries} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ DN Cache Hits
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.dncachehits} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ DN Cache Max Size
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.maxdncachesize} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ DN Cache Current Size
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.currentdncachesize} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ DN Cache Max Count
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.maxdncachecount} size="35" readOnly />
+ </Col>
+ </Row>
+ <Row className="ds-margin-top">
+ <Col sm={3}>
+ <ControlLabel>
+ DN Cache Current Count
+ </ControlLabel>
+ </Col>
+ <Col sm={3}>
+ <input type="text" value={this.props.data.currentdncachecount} size="35" readOnly />
+ </Col>
+ </Row>
+ </div>
+ </div>
+ </TabPane>
+ </TabContent>
+ </div>
+ </TabContainer>
+ </div>
+ );
+ }
+}
+
+SuffixMonitor.propTypes = {
+ suffix: PropTypes.string,
+ data: PropTypes.object,
+ bename: PropTypes.string,
+ reload: PropTypes.func,
+};
+
+SuffixMonitor.defaultProps = {
+ suffix: "",
+ data: {},
+ bename: "",
+ reload: noop,
+};
+
+export default SuffixMonitor;
diff --git a/src/cockpit/389-console/src/lib/notifications.jsx b/src/cockpit/389-console/src/lib/notifications.jsx
index a2b23e5..ad0b87f 100644
--- a/src/cockpit/389-console/src/lib/notifications.jsx
+++ b/src/cockpit/389-console/src/lib/notifications.jsx
@@ -25,7 +25,7 @@ class NotificationController extends React.Component {
<strong>{notification.header}</strong>
)}
{notification.type == "error" ? (
- <pre>{notification.message}</pre>
+ <pre className="ds-width-auto">{notification.message}</pre>
) : (
<span>{notification.message}</span>
)}
diff --git a/src/cockpit/389-console/src/lib/tools.jsx b/src/cockpit/389-console/src/lib/tools.jsx
index 442d032..5d482ba 100644
--- a/src/cockpit/389-console/src/lib/tools.jsx
+++ b/src/cockpit/389-console/src/lib/tools.jsx
@@ -56,3 +56,50 @@ export function log_cmd(js_func, desc, cmd_array) {
);
}
}
+
+// Convert DS timestamp to a friendly string: 20180921142257Z -> 10/21/2018, 2:22:57 PM
+export function get_date_string (timestamp) {
+ let year = timestamp.substr(0, 4);
+ let month = timestamp.substr(4, 2);
+ let day = timestamp.substr(6, 2);
+ let hour = timestamp.substr(8, 2);
+ let minute = timestamp.substr(10, 2);
+ let sec = timestamp.substr(12, 2);
+ let date = new Date(parseInt(year), parseInt(month), parseInt(day),
+ parseInt(hour), parseInt(minute), parseInt(sec));
+ return date.toLocaleString();
+}
+
+// Take two directory server tiemstamps and get the elapsed time
+export function get_date_diff(start, end) {
+ // Get the server's start up date
+ let year = start.substr(0, 4);
+ let month = start.substr(4, 2);
+ let day = start.substr(6, 2);
+ let hour = start.substr(8, 2);
+ let minute = start.substr(10, 2);
+ let sec = start.substr(12, 2);
+ let startDate = new Date(parseInt(year), parseInt(month), parseInt(day),
+ parseInt(hour), parseInt(minute), parseInt(sec));
+
+ // Get the servers current date
+ year = end.substr(0, 4);
+ month = end.substr(4, 2);
+ day = end.substr(6, 2);
+ hour = end.substr(8, 2);
+ minute = end.substr(10, 2);
+ sec = end.substr(12, 2);
+ let currDate = new Date(parseInt(year), parseInt(month), parseInt(day),
+ parseInt(hour), parseInt(minute), parseInt(sec));
+
+ // Generate pretty elapsed time string
+ let seconds = Math.floor((currDate - (startDate)) / 1000);
+ let minutes = Math.floor(seconds / 60);
+ let hours = Math.floor(minutes / 60);
+ let days = Math.floor(hours / 24);
+ hours = hours - (days * 24);
+ minutes = minutes - (days * 24 * 60) - (hours * 60);
+ seconds = seconds - (days * 24 * 60 * 60) - (hours * 60 * 60) - (minutes * 60);
+
+ return `${days} days, ${hours} hours, ${minutes} minutes, and ${seconds} seconds`;
+}
diff --git a/src/cockpit/389-console/src/monitor.html b/src/cockpit/389-console/src/monitor.html
deleted file mode 100644
index ba35e5c..0000000
--- a/src/cockpit/389-console/src/monitor.html
+++ /dev/null
@@ -1,916 +0,0 @@
-
- <div id="monitor-server-page" class="all-pages" hidden>
- <h3 class="ds-config-header">Server Information</h3>
- <div class="ds-container">
- <div class="ds-inline">
- <div>
- <label for="monitor-serverid" class="ds-label-xsm">Server Instance</label><input type="text"
- class="ds-ro-input" id="monitor-serverid" value="slapd-localhost" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-status" class="ds-label-xsm">Server Status</label><input type="text"
- class="ds-ro-input" id="monitor-status" value="Started" size="30" readOnly/>
- </div>
- </div>
- <div class="ds-divider"></div>
- <div class="ds-inline">
- <div>
- <label for="monitor-version" class="ds-label-xsm">Version</label><input type="text"
- class="ds-ro-input" id="monitor-version" value="1.4.0.5.20180220gitfeb11dc33" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-build" class="ds-label-xsm">Build Number</label><input type="text"
- class="ds-ro-input" id="monitor-build" value="B2018.051.1911" size="30" readOnly/>
- </div>
- </div>
- </div>
- <hr>
- <h3 class="ds-config-header">Server Statistics</h3>
- <div class="ds-container">
- <div class="ds-inline">
- <div>
- <label for="monitor-server-dtablesize" class="ds-monitor-label">Max File Descriptors</label><input type="text"
- class="ds-ro-input" id="monitor-server-dtablesize" value="1024" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-threads" class="ds-monitor-label">Threads</label><input type="text"
- class="ds-ro-input" id="monitor-server-threads" value="24" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-totalconnections" class="ds-monitor-label">Total Connections</label><input type="text"
- class="ds-ro-input" id="monitor-server-totalconnections" value="101" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-currentconnections" class="ds-monitor-label">Current Conections</label><input type="text"
- class="ds-ro-input" id="monitor-server-currentconnections" value="4" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-currentconnectionsatmaxthreads" class="ds-monitor-label">Conns At Max Threads</label><input type="text"
- class="ds-ro-input" id="monitor-server-currentconnectionsatmaxthreads" value="0" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-maxthreadsperconnhits" class="ds-monitor-label">Conns Hit Max Threads</label><input type="text"
- class="ds-ro-input" id="monitor-server-maxthreadsperconnhits" value="0" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-readwaiters" class="ds-monitor-label">Threads Waiting To Read</label><input type="text"
- class="ds-ro-input" id="monitor-server-readwaiters" value="0" size="12" readOnly/>
- </div>
- </div>
- <div class="ds-divider"></div>
- <div class="ds-inline">
- <div>
- <label for="monitor-server-opsinitiated" class="ds-monitor-label-med">Operations Started</label><input type="text"
- class="ds-ro-input" id="monitor-server-opsinitiated" value="0" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-opscompleted" class="ds-monitor-label-med">Operations Completed</label><input type="text"
- class="ds-ro-input" id="monitor-server-opscompleted" value="0" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-entriessent" class="ds-monitor-label-med">Entries Returned To Clients</label><input type="text"
- class="ds-ro-input" id="monitor-server-entriessent" value="0" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-bytessent" class="ds-monitor-label-med">Bytes Sent to Clients</label><input type="text"
- class="ds-ro-input" id="monitor-server-bytessent" value="0" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-starttime" class="ds-monitor-label-med">Server Started</label><input type="text"
- class="ds-ro-input" id="monitor-server-starttime" value="0" size="12" readOnly/>
- </div>
- <div>
- <label for="monitor-server-uptime" class="ds-monitor-label-med">Server Uptime</label><input type="text"
- class="ds-ro-input" id="monitor-server-uptime" value="0" size="12" readOnly/>
- </div>
- </div>
- </div>
- <div>
- <hr>
- <h3 class="ds-config-header">Connection Table</h3>
- <table id="monitor-conn-table" class="display ds-table" cellspacing="0" width="100%">
- <thead>
- <tr class="ds-table-header">
- <th>Connection Opened</th>
- <th>IP Address</th>
- <th>Connection ID</th>
- <th>Operations Started</th>
- <th>Operations Completed</th>
- <th>Bind DN</th>
- <th>Read/Write</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>2017023402340234Z</td>
- <td>127.0.0.1</td>
- <td>1</td>
- <td>10</td>
- <td>10</td>
- <td>cn=Directory Manager</td>
- <td>-</td>
- </tr>
- <tr>
- <td>2017023402340234Z</td>
- <td>::1</td>
- <td>11</td>
- <td>102</td>
- <td>101</td>
- <td>uid=mreynolds,ou=people,ou=redhat,dc=example,dc=com</td>
- <td>-</td>
- </tr>
- </tbody>
- </table>
- <p></p>
- </div>
- </div>
-
- <div id="monitor-db-page" class="all-pages" hidden>
- <h3 class="ds-config-header">Database Monitoring</h3>
- <div class="ds-container">
-
- <div id="monitor-db-tree" class="jstree-open ds-monitor-tree">
- <ul>
- <li class="jstree-open ds-treenode" data-jstree='{"icon":"glyphicon glyphicon-tasks", "opened":true, "selected":true}' id="monitor-db-main">Database Performance
- <ul>
- <li title="suffix" id="monitor-suffix-dc=red,dc=hat,dc=com,dc=lab,dc=example,dc=com"
- data-jstree='{"icon":"glyphicon glyphicon-tree-conifer"}'>dc=red,dc=hat,dc=com,dc=lab,dc=example,dc=com
- <ul>
- <li title="sub suffix" id="monitor-suffix-ou=People,dc=example,dc=com" data-jstree='{"icon":"glyphicon glyphicon-leaf"}'>ou=People,dc=example,dc=com</li>
- </ul>
- </li>
- <li title="suffix" id="monitor-suffix-o=ipaca" data-jstree='{"icon":"glyphicon glyphicon-tree-conifer"}'>o=ipaca</li>
- </ul>
- </li>
- </ul>
- </div>
-
- <div class="ds-divider"></div>
-
- <div name="tree content">
- <div id="db-content">
- <h3 class="ds-config-header">Database Performance Statistics</h3>
- <hr>
- <div class="ds-container">
- <div>
- <div class="pct-donut-chart-pf example-donut-chart-utilization ds-container ds-chart-center">
- <div class="pct-donut-chart-pf-chart">
- <div title="The database cache hit ratio. If the chart is RED then the hit ratio is below 90% and might require further cache tuning" id="monitor-db-cache-hitratio-chart"></div>
- <span class="pct-donut-chart-pf-label ds-center">
- <b>DB Cache Hit Ratio</b>
- </span>
- </div>
- </div>
-
- <hr class="ds-hr">
- <div class="ds-inline">
- <div>
- <label for="monitor-db-dbcachehitratio" class="ds-monitor-label">Database Cache Hit Ratio</label><input type="text"
- class="ds-input" id="monitor-db-dbcachehitratio" value="99%" size="20" readOnly/>
- </div>
- <div>
- <label for="monitor-db-dbcachetries" class="ds-monitor-label">Database Cache Tries</label><input type="text"
- class="ds-input" id="monitor-db-dbcachetries" value="19541" size="20" readOnly/>
- </div>
- <div>
- <label for="monitor-db-dbcachehits" class="ds-monitor-label">Database Cache Hits</label><input type="text"
- class="ds-input" id="monitor-db-dbcachehits" value="19507" size="20" readOnly/>
- </div>
- <div>
- <label for="monitor-db-dbcachepagein" class="ds-monitor-label">Cache Pages Read</label><input type="text"
- class="ds-input" id="monitor-db-dbcachepagein" value="34" size="20" readOnly/>
- </div>
- <div>
- <label for="monitor-db-dbcachepageout" class="ds-monitor-label">Cache Pages Written</label><input type="text"
- class="ds-input" id="monitor-db-dbcachepageout" value="35" size="20" readOnly/>
- </div>
- <div>
- <label for="monitor-db-dbcacheroevict" class="ds-monitor-label">Read-Only Page Evictions</label><input type="text"
- class="ds-input" id="monitor-db-dbcacheroevict" value="0" size="20" readOnly/>
- </div>
- <div>
- <label for="monitor-db-dbcacherwevict" class="ds-monitor-label">Read-Write Page Evictions</label><input type="text"
- class="ds-input" id="monitor-db-dbcacherwevict" value="0" size="20" readOnly/>
- </div>
- </div>
- </div>
-
- <div class="ds-divider"></div>
- <div class="ds-divider"></div>
-
- <div>
- <div class="pct-donut-chart-pf example-donut-chart-utilization ds-container">
- <div class="pct-donut-chart-pf-chart ds-chart-left">
- <div title="The NDN cache hit ratio. If the chart is RED then the hit ratio is below 90% and might require further cache tuning" id="monitor-ndn-cache-hitratio-chart"></div>
- <span class="pct-donut-chart-pf-label">
- <b>NDN Cache Hit Ratio</b>
- </span>
- </div>
- <div class="pct-donut-chart-pf-chart ds-chart-right">
- <div title="How much of the allocated cache space is used (max size vs current size). If the chart is RED then you should to increase the max cache size because the cache hit ratio is below 90%"
- id="monitor-ndn-cache-util-chart"></div>
- <span class="pct-donut-chart-pf-label">
- <b>NDN Cache Utilization</b>
- </span>
- </div>
- </div>
- <hr class="ds-hr">
- <div class="ds-inline">
- <div>
- <label title ="Normalized DN Cache hit ratio" for="monitor-db-normalizeddncachehitratio" class="ds-monitor-label">NDN Cache Hit Ratio</label><input type="text"
- class="ds-input" id="monitor-db-normalizeddncachehitratio" value="83%" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache tries" for="monitor-db-normalizeddncachetries" class="ds-monitor-label">NDN Cache Tries</label><input type="text"
- class="ds-input" id="monitor-db-normalizeddncachetries" value="7680" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache hits" for="monitor-db-normalizeddncachehits" class="ds-monitor-label">NDN Cache Hits</label><input type="text"
- class="ds-input" id="monitor-db-normalizeddncachehits" value="6302" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache evictions" for="monitor-db-normalizeddncacheevictions" class="ds-monitor-label">NDN Cache Evictions</label><input type="text"
- class="ds-input" id="monitor-db-normalizeddncacheevictions" value="0" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache max size in bytes" for="monitor-db-maxnormalizeddncachesize" class="ds-monitor-label">NDN Cache Max Size</label><input type="text"
- class="ds-input" id="monitor-db-maxnormalizeddncachesize" value="25165824" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache current size of the cache in bytes" for="monitor-db-currentnormalizeddncachesize" class="ds-monitor-label">NDN Current Cache Size</label><input type="text"
- class="ds-input" id="monitor-db-currentnormalizeddncachesize" value="19891200" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache DN count" for="monitor-db-currentnormalizeddncachecount" class="ds-monitor-label">NDN Cache DN Count</label><input type="text"
- class="ds-input" id="monitor-db-currentnormalizeddncachecount" value="1276" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache thread size in bytes" for="monitor-db-normalizeddncachethreadsize" class="ds-monitor-label">NDN Cache Thread Size</label><input type="text"
- class="ds-input" id="monitor-db-normalizedndncachethreadsize" value="1048576" size="30" readOnly/>
- </div>
- <div>
- <label title ="Normalized DN Cache thread slot size" for="monitor-db-normalizeddnslots" class="ds-monitor-label">NDN Cache Thread Slots</label><input type="text"
- class="ds-input" id="monitor-db-normalizeddnslots" value="8192" size="30" readOnly/>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <!-- Suffix page -->
- <div id="monitor-suffix-page" class="ds-tree-content" hidden>
- <h3 class="ds-config-header" id="monitor-suffix-header"></h3>
- <hr>
- <div class="ds-container">
- <div class="">
- <!-- <div id="monitor-entry-cache-chart" class="pie-chart-pf example-pie-chart-mini"></div> -->
- <div class="pct-donut-chart-pf example-donut-chart-utilization ds-container">
- <div class="pct-donut-chart-pf-chart ds-chart-left">
- <div title="The entry cache hit ratio. If the chart is RED then the hit ratio is below 90% and might require further cache tuning" id="monitor-entry-cache-hitratio-chart"></div>
- <span class="pct-donut-chart-pf-label">
- <b>Entry Cache Hit Ratio</b>
- </span>
- </div>
- <div class="pct-donut-chart-pf-chart ds-chart-right">
- <div title="How much of the allocated cache space is used (max size vs current size). If the chart is RED then you should to increase the max cache size because the cache hit ratio is below 90%"
- id="monitor-entry-cache-util-chart"></div>
- <span class="pct-donut-chart-pf-label">
- <b>Entry Cache Utilization</b>
- </span>
- </div>
- </div>
- <p></p>
- <hr class="ds-hr">
- <div class="ds-inline">
- <div>
- <label for="monitor-be-entrycachehitratio" class="ds-label-med">Entry Cache Hit Ratio</label><input type="text"
- class="ds-ro-input" id="monitor-be-entrycachehitratio" value="99%" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-be-entrycachetries" class="ds-label-med">Entry Cache Tries</label><input type="text"
- class="ds-ro-input" id="monitor-be-entrycachetries" value="3058" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-be-entrycachehits" class="ds-label-med">Database Cache Hits</label><input type="text"
- class="ds-ro-input" id="monitor-be-entrycachehits" value="3001" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-be-maxentrycachesize" class="ds-label-med">Entry Cache Max Size</label><input type="text"
- class="ds-ro-input" id="monitor-be-maxentrycachesize" value="512000" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-be-currententrycachesize" class="ds-label-med">Entry Cache Current Size</label><input type="text"
- class="ds-ro-input" id="monitor-be-currententrycachesize" value="389000" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-be-maxentrycachecount" class="ds-label-med">Entry Cache Max Entries</label><input type="text"
- class="ds-ro-input" id="monitor-be-maxentrycachecount" value="-1" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-be-currententrycachecount" class="ds-label-med">Entry Cache Count</label><input type="text"
- class="ds-ro-input" id="monitor-be-currententrycachecount" value="105" size="30" readOnly/>
- </div>
- </div>
- </div>
- <div class="ds-divider"></div>
- <div class="ds-divider"></div>
- <div>
- <div class="pct-donut-chart-pf example-donut-chart-utilization ds-container">
- <div class="pct-donut-chart-pf-chart ds-chart-left">
- <div title="The entry cache hit ratio" id="monitor-dn-cache-hitratio-chart"></div>
- <span class="pct-donut-chart-pf-label">
- <b>DN Cache Hit Ratio</b>
- </span>
- </div>
- <div class="pct-donut-chart-pf-chart ds-chart-right">
- <div title="How much of the allocated cache space is used (max size vs current size). If the chart is RED then you should to increase the max cache size because the cache hit ratio is below 90%"
-
- id="monitor-dn-cache-util-chart"></div>
- <span class="pct-donut-chart-pf-label">
- <b>DN Cache Utilization</b>
- </span>
- </div>
- </div>
- <p></p>
- <hr class="ds-hr">
- <div class="ds-inline">
- <div>
- <label title ="" for="monitor-be-dncachehitratio" class="ds-label-med">DN Cache Hit Ratio</label><input type="text"
- class="ds-ro-input" id="monitor-be-dncachehitratio" value="100%" size="30" readOnly/>
- </div>
- <div>
- <label title ="" for="monitor-be-dncachetries" class="ds-label-med">DN Cache Tries</label><input type="text"
- class="ds-ro-input" id="monitor-be-dncachetries" value="105" size="30" readOnly/>
- </div>
- <div>
- <label title ="" for="monitor-be-dncachehits" class="ds-label-med">DN Cache Hits</label><input type="text"
- class="ds-ro-input" id="monitor-be-dncachehits" value="105" size="30" readOnly/>
- </div>
- <div>
- <label title ="" for="monitor-be-maxdncachesize" class="ds-label-med">DN Cache Max Size</label><input type="text"
- class="ds-ro-input" id="monitor-be-maxdncachesize" value="16777216" size="30" readOnly/>
- </div>
- <div>
- <label title ="" for="monitor-be-currentdncachesize" class="ds-label-med">DN Cache Current Size</label><input type="text"
- class="ds-ro-input" id="monitor-be-currentdncachesize" value="16809" size="30" readOnly/>
- </div>
- <div>
- <label title ="" for="monitor-be-maxdncachecount" class="ds-label-med">DN Cache Max Count</label><input type="text"
- class="ds-ro-input" id="monitor-be-maxdncachecount" value="-1" size="30" readOnly/>
- </div>
- <div>
- <label title ="" for="monitor-be-currentdncachecount" class="ds-label-med">DN Cache Current Count</label><input type="text"
- class="ds-ro-input" id="monitor-be-currentdncachecount" value="105" size="30" readOnly/>
- </div>
- </div>
- </div>
- </div>
-
- <div>
- <hr>
- <h3 class="ds-config-header">Index Statistics</h3>
- <hr class="ds-hr">
- <table id="monitor-index-table" class="display ds-table" cellspacing="0" width="100%">
- <thead>
- <tr class="ds-table-header">
- <th>Attribute</th>
- <th>Cache Hits</th>
- <th>Cache Misses</th>
- <th>Pages Read</th>
- <th>Pages Written</th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>uid</td>
- <td>101</td>
- <td>10</td>
- <td>1</td>
- <td>2</td>
- </tr>
- <tr>
- <td>cn</td>
- <td>705</td>
- <td>3</td>
- <td>2</td>
- <td>2</td>
- </tr>
- </tbody>
- </table>
- <p></p>
- </div>
- </div>
- </div>
-
- </div>
- </div>
-
- <div id="monitor-snmp-page" class="all-pages" hidden>
- <h3 class="ds-config-header">SNMP Counters</h3>
- <hr>
- <div class="ds-container">
- <div class="ds-inline">
- <div>
- <label for="monitor-snmp-anonymousbinds" class="ds-label-med">Anonymous Binds</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-anonymousbinds" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-unauthbinds" class="ds-label-med">Unauthenticated Binds</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-unauthbinds" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-simpleauthbinds" class="ds-label-med">Simple Auth Binds</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-simpleauthbinds" value="77" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-strongauthbinds" class="ds-label-med">Strong Auth Binds</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-strongauthbinds" value="0" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-inops" class="ds-label-med">Initiated Operations</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-inops" value="818" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-compareops" class="ds-label-med">Compare Operations</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-compareops" value="1" size="30" readOnly/>
- </div>
- <div>
- <label for="mnitor-snmp-addentryops" class="ds-label-med">Add Operations</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-addentryops" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-removeentryops" class="ds-label-med">Delete Operations</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-removeentryops" value="50" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-modifyentryops" class="ds-label-med">Modify Operations</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-modifyentryops" value="501" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-modifyrdnops" class="ds-label-med">ModRDN Operations</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-modifyrdnops" value="0" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-searchops" class="ds-label-med">Search Operations</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-searchops" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-onelevelsearchops" class="ds-label-med">One Level Searches</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-onelevelsearchops" value="2" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-wholesubtreesearchops" class="ds-label-med">Whole Tree Searches</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-wholesubtreesearchops" value="5" size="30" readOnly/>
- </div>
- </div>
- <div class="ds-divider"></div>
- <div class="ds-divider"></div>
- <div class="ds-inline">
- <div>
- <label for="monitor-snmp-referrals" class="ds-label-med">Referrals</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-referrals" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-referralsreturned" class="ds-label-med">Returned Referrals</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-referralsreturned" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-bindsecurityerrors" class="ds-label-med">Bind Security Errors</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-bindsecurityerrors" value="0" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-securityerrors" class="ds-label-med">Security Errors</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-securityerrors" value="0" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-errors" class="ds-label-med">Errors</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-errors" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-connections" class="ds-label-med">Current Connections</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-connections" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-connectionseq" class="ds-label-med">Total Connections</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-connectionseq" value="50001" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-connectionsinmaxthreads" class="ds-label-med">Conns in Max Threads</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-connectionsinmaxthreads" value="0" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-connectionsmaxthreadscount" class="ds-label-med">Conns Hit Max Threads</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-connectionsmaxthreadscount" value="5" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-bytesrecv" class="ds-label-med">Bytes Received</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-bytesrecv" value="4563" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-bytessent" class="ds-label-med">Bytes Sent</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-bytessent" value="993068" size="30" readOnly/>
- </div>
- <div>
- <label for="monitor-snmp-entriesreturned" class="ds-label-med">Entries Sent</label><input type="text"
- class="ds-ro-input" id="monitor-snmp-entriesreturned" value="5" size="30" readOnly/>
- </div>
- </div>
- </div>
- <p></p>
- </div>
-
- <div id="monitor-log-access-page" class="all-pages" hidden>
- <h3>Access Log</h3>
- <hr>
- <label for="accesslog-lines"> Log Lines To Show</label><select
- class="btn btn-default dropdown ds-log-dropdown" id="accesslog-lines">
- <option>50</option>
- <option>100</option>
- <option>200</option>
- <option>300</option>
- <option>400</option>
- <option>500</option>
- <option>1000</option>
- <option>2000</option>
- <option>5000</option>
- <option>10000</option>
- </select><button id="accesslog-refresh-btn" class="ds-adj-btn">Refresh</button><label
- class="ds-left-margin">Continuously Refresh<input type="checkbox" class="ds-sm-left-margin" id="accesslog-cont-refresh"></label>
- <textarea id="accesslog-area" class="ds-logarea" readonly></textarea>
- <p></p>
- </div>
-
- <div id="monitor-log-audit-page" class="all-pages" hidden>
- <h3>Audit Log</h3>
- <hr>
- <label for="auditlog-lines"> Log Lines To Show</label><select
- class="btn btn-default dropdown ds-log-dropdown" id="auditlog-lines">
- <option>50</option>
- <option>100</option>
- <option>200</option>
- <option>300</option>
- <option>400</option>
- <option>500</option>
- <option>1000</option>
- <option>2000</option>
- <option>5000</option>
- <option>10000</option>
- </select><button id="auditlog-refresh-btn" class="ds-adj-btn">Refresh</button><label
- class="ds-left-margin">Continuously Refresh<input type="checkbox" class="ds-sm-left-margin" id="auditlog-cont-refresh"></label>
- <textarea id="auditlog-area" class="ds-logarea" readonly></textarea>
- <p></p>
- </div>
-
- <div id="monitor-log-auditfail-page" class="all-pages" hidden>
- <h3>Audit Failure Log</h3>
- <hr>
- <label for="auditfaillog-lines"> Log Lines To Show</label><select
- class="btn btn-default dropdown ds-log-dropdown" id="auditfaillog-lines">
- <option>50</option>
- <option>100</option>
- <option>200</option>
- <option>300</option>
- <option>400</option>
- <option>500</option>
- <option>1000</option>
- <option>2000</option>
- <option>5000</option>
- <option>10000</option>
- </select><button id="auditfaillog-refresh-btn" class="ds-adj-btn">Refresh</button><label
- class="ds-left-margin">Continuously Refresh<input type="checkbox" class="ds-sm-left-margin" id="auditfaillog-cont-refresh"></label>
- <textarea id="auditfaillog-area" class="ds-logarea" readonly></textarea>
- <p></p>
- </div>
-
- <div id="monitor-log-errors-page" class="all-pages" hidden>
- <h3>Errors Log</h3>
- <hr>
- <label for="errorslog-lines"> Log Lines To Show</label><select
- class="btn btn-default dropdown ds-left-margin" id="errorslog-lines">
- <option>50</option>
- <option>100</option>
- <option>200</option>
- <option>300</option>
- <option>400</option>
- <option>500</option>
- <option>1000</option>
- <option>2000</option>
- <option>5000</option>
- <option>10000</option>
- </select><button id="errorslog-refresh-btn" class="ds-adj-btn">Refresh</button><label
- class="ds-left-margin">Continuously Refresh<input type="checkbox" class="ds-sm-left-margin" id="errorslog-cont-refresh"></label><div
- class="dropdown ds-float-right"><label
- for="errorslog-sev-level">Filter Logging By Severity Level</label><select
- class="btn btn-default dropdown ds-left-margin" id="errorslog-sev-level">
- <option>Everything</option>
- <option>Error Messages</option>
- <option>Info Messages</option>
- <option disabled>──────────</option>
- <option>Emergency</option>
- <option>Alert</option>
- <option>Critical</option>
- <option>Error</option>
- <option>Warning</option>
- <option>Notice</option>
- <option>Info</option>
- <option>Debug</option>
- </select>
- </div>
- <textarea id="errorslog-area" class="ds-logarea" readonly></textarea>
- <p></p>
- </div>
-
-
-
- <div id="monitor-repl-page" class="all-pages" hidden>
- <h3>Replication Monitoring for <select class="btn btn-default dropdown" id="monitor-repl-backend-list">
- <option>dc=example,dc=com</option></select></h3>
- <hr>
- <h4>Replication Agreements</h4>
- <table id="monitor-repl-table" class="display ds-table" cellspacing="0" width="100%">
- <thead>
- <tr class="ds-table-header">
- <th>Agreement</th>
- <th>Replica</th>
- <th>Enabled</th>
- <th>Replication Lag</th>
- <th>Replication State</th>
- <th></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>me2localhost</td>
- <td>localhost.localdomain:5555</td>
- <td>Yes</td>
- <td>00:00:00</td>
- <td data-sort="good"><div class="ds-repl-state-good"><span class="glyphicon glyphicon-thumbs-up"></span></div></td>
- <td><button class="btn btn-default ds-agmt-dropdown-button repl-detail-btn" data-toggle="modal" data-target="#monitor-agmt-form" type="button">View Details</button></td>
- </tr>
- <tr>
- <td>me2beaker</td>
- <td>lab1.localdomain.com:389</td>
- <td>Yes</td>
- <td >00:00:02</td>
- <td data-sort="good"><div class="ds-repl-state-good"><span class="glyphicon glyphicon-thumbs-up"></span></div></td>
- <td><button class="btn btn-default ds-agmt-dropdown-button repl-detail-btn" data-toggle="modal" data-target="#monitor-agmt-form" type="button">View Details</button></td>
- </tr>
- <tr>
- <td>me2fedora</td>
- <td>lab45.localdomain.com:389</td>
- <td>Yes</td>
- <td>00:09:02</td>
- <td data-sort="good"><div class="ds-repl-state-good"><span class="glyphicon glyphicon-thumbs-up"></span></div></td>
- <td><button class="btn btn-default ds-agmt-dropdown-button repl-detail-btn" data-toggle="modal" data-target="#monitor-agmt-form" type="button">View Details</button></td>
- </tr>
- <tr>
- <td>me2beaker</td>
- <td>lab11.localdomain.com:389</td>
- <td>Yes</td>
- <td class="ds-repl-lag-bad">00:45:02</td>
- <td data-sort="bad"><div class="ds-repl-state-bad"><span class="glyphicon glyphicon-thumbs-down"></span></div></td>
- <td><button class="btn btn-default ds-agmt-dropdown-button repl-detail-btn" data-toggle="modal" data-target="#monitor-agmt-form" type="button">View Details</button></td>
- </tr>
- </tbody>
- </table>
- <p></p>
- <hr>
- <h4>Windows Synchronization Agreements</h4>
- <table id="monitor-winsync-table" class="display ds-table" cellspacing="0" width="100%">
- <thead>
- <tr class="ds-table-header">
- <th>Agreement</th>
- <th>Windows Host/Port</th>
- <th>Windows Suffix</th>
- <th>Directory Server Suffix</th>
- <th>Replication State</th>
- <th></th>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>my-winsync-agmt</td>
- <td>localhost.domain.com:389</td>
- <td>cn=users,dc=example,dc=com</td>
- <td>ou=people,dc=example,dc=com</td>
- <td data-sort="good"><div class="ds-repl-state-good"><span class="glyphicon glyphicon-thumbs-up"></span></div></td>
- <td><button class="btn btn-default ds-agmt-dropdown-button repl-winsync-detail-btn" data-toggle="modal"
- data-target="#monitor-winsync-agmt-form" type="button">View Details</button></td>
- </tr>
- </tbody>
- </table>
- <p></p>
- </div>
-
-
- <!-- Agmt detail modal -->
-
- <div class="modal fade" id="monitor-agmt-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="repl-agmt-header" aria-hidden="true">
- <div class="modal-dialog ds-modal-wide">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
- <span class="pficon pficon-close"></span>
- </button>
- <h4 class="modal-title" id="repl-agmt-header">Replication Agreement Details</h4>
- </div>
- <div class="modal-body">
- <form class="form-horizontal">
- <div class="ds-container">
- <div class="ds-inline">
- <div>
- <label for="monitor-agmt-lag" class="ds-label-med" title="The replication time lag between the supplier and its consumer">Replication Lag</label><input
- class="ds-input" type="text" id="monitor-agmt-lag" size="22" value="00:01" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicaupdateinprogress" class="ds-label-med" title="The replication time lag between the supplier and its consumer">Replication In Progress</label><input
- class="ds-input" type="text" id="monitor-nsds5replicaupdateinprogress" size="22" value="FALSE" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5beginreplicarefresh" class="ds-label-med" title="The replication time lag between the supplier and its consumer">Replication Init In Progress</label><input
- class="ds-input" type="text" id="monitor-nsds5beginreplicarefresh" size="22" value="" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicachangessentsincestartup" class="ds-label-med" title="The replication time lag between the supplier and its consumer">Changes Sent Since Startup</label><input
- class="ds-input" type="text" id="monitor-nsds5replicachangessentsincestartup" size="22" value="1/0" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicalastupdatestart" class="ds-label-med" title="The time when the last update was sent to the consumer">Last Update Started</label><input
- class="ds-input" type="text" id="monitor-nsds5replicalastupdatestart" size="22" value="Fri Mar 09 09:06:03 EST 2018" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicalastupdateend" class="ds-label-med" title="The the when the last updated was finished">Last Update Ended</label><input
- class="ds-input" type="text" id="monitor-nsds5replicalastupdateend" size="22" value="Fri Mar 09 09:06:04 EST 2018" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicalastinitstart" class="ds-label-med" title="The the when the last updated was finished">Last Init Started</label><input
- class="ds-input" type="text" id="monitor-nsds5replicalastinitstart" size="22" value="Fri Mar 09 09:06:04 EST 2018" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicalastinitend" class="ds-label-med" title="The the when the last updated was finished">Last Init Ended</label><input
- class="ds-input" type="text" id="monitor-nsds5replicalastinitend" size="22" value="Fri Mar 09 09:06:04 EST 2018" readOnly/>
- </div>
- </div>
- <div class="ds-divider"></div>
- <div class="ds-inline">
- <div>
- <label for="monitor-nsds5replicahost" class="ds-label-med" title="The replica/consumer host name">Replica Host</label><input
- class="ds-input" type="text" id="monitor-nsds5replicahost" size="22" value="localhost.localdomain" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicaport" class="ds-label-med" title="The replica/consumer port number">Replica Port</label><input
- class="ds-input" type="text" id="monitor-nsds5replicaport" size="22" value="389" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicaroot" class="ds-label-med" title="The suffix that is being replicated">Replicated Suffix</label><input
- class="ds-input" type="text" id="monitor-nsds5replicaroot" size="22" value="dc=example,dc=com" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicatransportinfo" class="ds-label-med" title="The replication agreement connection protocol">Replication Conn Protocol</label><input
- class="ds-input" type="text" id="monitor-nsds5replicatransportinfo" size="22" value="LDAPS" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicabindmethod" class="ds-label-med" title="The replication bind method">Replication Bind Method</label><input
- class="ds-input" type="text" id="monitor-nsds5replicabindmethod" size="22" value="SIMPLE" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicabinddn" class="ds-label-med" title="The replication bind method">Replication Bind DN</label><input
- class="ds-input" type="text" id="monitor-nsds5replicabinddn" size="22" value="uid=replication manager,cn=config" readOnly/>
- </div>
- <div>
- <label for="monitor-nsds5replicaenabled" class="ds-label-med" title="The replication bind method">Agreement State</label><input
- class="ds-input" type="text" id="monitor-nsds5replicaenabled" size="22" value="Disabled" readOnly/>
- </div>
- </div>
- </div>
- <div>
- <label for="monitor-nsds5replicalastinitstatus" class="ds-label-med" title="The replication bind method">Last Initialization Status</label>
- <textarea id="monitor-nsds5replicalastinitstatus" rows="5" class="ds-agmt-textarea" readonly>Error (0) Total Update Succeeded</textarea>
- <p></p>
- <label for="monitor-nsds5replicalastupdatestatus" class="ds-label-med" title="The replication bind method">Last Update Status</label>
- <textarea id="monitor-nsds5replicalastupdatestatus" rows="5" class="ds-agmt-textarea" readonly>Error (0) Replica acquired successfully: Incremental update succeeded</textarea>
- </div>
- </form>
- </div>
- <div class="modal-footer ds-modal-footer">
- <button type="button" class="btn btn-default ds-button-left" id="monitor-test-winsync-repl" data-dismiss="modal">Test Replication</button>
- <button type="button" class="btn btn-default ds-button-right" data-dismiss="modal">Close</button>
- </div>
- </div>
- </div>
- </div>
-
-
- <!-- WINSYNC Agmt detail modal -->
-
- <div class="modal fade" id="monitor-winsync-agmt-form" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="repl-winsync-agmt-header" aria-hidden="true">
- <div class="modal-dialog ds-modal-wide">
- <div class="modal-content">
- <div class="modal-header">
- <button type="button" class="close" data-dismiss="modal" aria-hidden="true" aria-label="Close">
- <span class="pficon pficon-close"></span>
- </button>
- <h4 class="modal-title" id="repl-winsync-agmt-header">Winsync Agreement Details</h4>
- </div>
- <div class="modal-body">
- <form class="form-horizontal">
- <div class="ds-container">
- <div class="ds-inline">
- <div>
- <label for="monitor-winsync-nsds5replicaupdateinprogress" class="ds-label-med" title="The replication time lag between the supplier and its consumer">Replication In Progress</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicaupdateinprogress" size="22" value="FALSE" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5beginreplicarefresh" class="ds-label-med" title="The replication time lag between the supplier and its consumer">Replication Init In Progress</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5beginreplicarefresh" size="22" value="" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicachangessentsincestartup" class="ds-label-med" title="The replication time lag between the supplier and its consumer">Changes Sent Since Startup</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicachangessentsincestartup" size="22" value="1/0" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicalastupdatestart" class="ds-label-med" title="The time when the last update was sent to the consumer">Last Update Started</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicalastupdatestart" size="22" value="Fri Mar 09 09:06:03 EST 2018" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicalastupdateend" class="ds-label-med" title="The the when the last updated was finished">Last Update Ended</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicalastupdateend" size="22" value="Fri Mar 09 09:06:04 EST 2018" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicalastinitstart" class="ds-label-med" title="The the when the last updated was finished">Last Init Started</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicalastinitstart" size="22" value="Fri Mar 09 09:06:04 EST 2018" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicalastinitend" class="ds-label-med" title="The the when the last updated was finished">Last Init Ended</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicalastinitend" size="22" value="Fri Mar 09 09:06:04 EST 2018" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicaenabled" class="ds-label-med" title="The replication bind method">Agreement State</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicaenabled" size="22" value="Disabled" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds7newwinusersyncenabled" class="ds-label-med" title="The the when the last updated was finished">Sync New Users Enable</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds7newwinusersyncenabled" size="22" value="on" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds7newwingroupsyncenabled" class="ds-label-med" title="The the when the last updated was finished">Sync New Groups Enabled</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds7newwingroupsyncenabled" size="22" value="on" readOnly/>
- </div>
- </div>
- <div class="ds-divider"></div>
- <div class="ds-inline">
- <div>
- <label for="monitor-winsync-nsds5replicahost" class="ds-label-med" title="The replica/consumer host name">Replica Host</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicahost" size="22" value="localhost.localdomain" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-winsync-nsds5replicaport" class="ds-label-med" title="The replica/consumer port number">Replica Port</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicaport" size="22" value="389" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicaroot" class="ds-label-med" title="The suffix that is being replicated">Replicated Suffix</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicaroot" size="22" value="dc=example,dc=com" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicatransportinfo" class="ds-label-med" title="The replication agreement connection protocol">Replication Conn Protocol</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicatransportinfo" size="22" value="LDAPS" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicabindmethod" class="ds-label-med" title="The replication bind method">Replication Bind Method</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicabindmethod" size="22" value="SIMPLE" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds5replicabinddn" class="ds-label-med" title="The replication bind method">Replication Bind DN</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds5replicabinddn" size="22" value="uid=replication manager,cn=config" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds7windowsreplicasubtree" class="ds-label-med" title="The replication bind method">Windows Subtree</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds7windowsreplicasubtree" size="22" value="cn=Users,dc=example,dc=com" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds7directoryreplicasubtree" class="ds-label-med" title="The replication bind method">Directory Server Subtree</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds7directoryreplicasubtree" size="22" value="ou=People, dc=example,dc=com" readOnly/>
- </div>
- <div>
- <label for="monitor-winsync-nsds7windowsdomain" class="ds-label-med" title="The replication bind method">Windows Domain</label><input
- class="ds-input" type="text" id="monitor-winsync-nsds7windowsdomain" size="22" value="example.com" readOnly/>
- </div>
- </div>
- </div>
- <p></p>
- <div>
- <label for="monitor-winsync-nsds5replicalastinitstatus" class="ds-label-med" title="The replication bind method">Last Initialization Status</label>
- <textarea id="monitor-winsync-nsds5replicalastinitstatus" rows="5" class="ds-agmt-textarea" readonly>Error (0) Total Update Succeeded</textarea>
- <p></p>
- <label for="monitor-winsync-nsds5replicalastupdatestatus" class="ds-label-med" title="The replication bind method">Last Update Status</label>
- <textarea id="monitor-winsync-nsds5replicalastupdatestatus" rows="5" class="ds-agmt-textarea" readonly>Error (0) Replica acquired successfully: Incremental update succeeded</textarea>
- </div>
- </form>
- </div>
- <div class="modal-footer ds-modal-footer">
- <button type="button" class="btn btn-default ds-button-left" id="monitor-test-winsync-repl" data-dismiss="modal">Test Replication</button>
- <button type="button" class="btn btn-default ds-button-right" data-dismiss="modal">Close</button>
- </div>
- </div>
- </div>
- </div>
diff --git a/src/cockpit/389-console/src/monitor.js b/src/cockpit/389-console/src/monitor.js
deleted file mode 100644
index 1774d15..0000000
--- a/src/cockpit/389-console/src/monitor.js
+++ /dev/null
@@ -1,398 +0,0 @@
-
-var accesslog_cont_refresh;
-var auditlog_cont_refresh;
-var auditfaillog_cont_refresh;
-var errorslog_cont_refresh;
-
-var sev_emerg = " - EMERG - ";
-var sev_crit = " - CRIT - ";
-var sev_alert = " - ALERT - ";
-var sev_err = " - ERR - ";
-var sev_warn = " - WARN - ";
-var sev_notice = " - NOTICE - ";
-var sev_info = " - INFO - ";
-var sev_debug = " - DEBUG - ";
-var sev_levels = {"Emergency": sev_emerg,
- "Critical": sev_crit,
- "Alert": sev_alert,
- "Error": sev_err,
- "Warning": sev_warn,
- "Notice": sev_notice,
- "Info": sev_info,
- "Debug": sev_debug
- };
-var sev_all_errs = [sev_emerg, sev_crit, sev_alert, sev_err];
-var sev_all_info = [sev_warn, sev_notice, sev_info, sev_debug];
-
-
-function gen_ratio_chart(ratio, chart ) {
- var c3ChartDefaults = patternfly.c3ChartDefaults();
- var donutConfig = c3ChartDefaults.getDefaultDonutConfig(ratio + "%");
- var miss = 100 - ratio;
- var donut_color = patternfly.pfPaletteColors.lightGreen;
- if (ratio < 90) {
- donut_color = patternfly.pfPaletteColors.red;
- }
- donutConfig.bindto = chart;
- donutConfig.data = {
- type: "donut",
- columns: [
- ["Hit Ratio", ratio],
- ["Miss", miss],
- ],
- colors: {
- 'Hit Ratio': donut_color,
- 'Miss': "#D8D8D8"
- },
- order: null
- };
- donutConfig.size = {
- width: 120,
- height: 80
- };
-
- c3.generate(donutConfig);
-};
-
-function gen_util_chart(used, maxsize, hitratio, chart ) {
- var c3ChartDefaults = patternfly.c3ChartDefaults();
- var ratio = Math.round((used / maxsize) * 100);
- var donutConfig = c3ChartDefaults.getDefaultDonutConfig(ratio + "%");
- var avail = maxsize - used;
- donutConfig.bindto = chart;
- var donut_color = patternfly.pfPaletteColors.lightGreen;
- if (hitratio < 90 && ratio > 90) {
- donut_color = patternfly.pfPaletteColors.red;
- }
-
- donutConfig.data = {
- type: "donut",
- columns: [
- ["Used", used],
- ["Available", avail],
- ],
- colors: {
- 'Used': donut_color,
- 'Available': "#D8D8D8"
- },
- order: null
- };
- donutConfig.size = {
- width: 120,
- height: 80
- };
- c3.generate(donutConfig);
-};
-
-/*
- * Refresh logs
- */
-function refresh_access_log () {
- var access_log = "/var/log/dirsrv/" + server_id + "/access"; // TODO - get actual log location from config
- var lines = $("#accesslog-lines").val();
- var logging = cockpit.spawn(["tail", "-" + lines, access_log],
- { "superuser": "try" }).done(function(data) {
- $("#accesslog-area").text(data);
- });
-}
-
-function refresh_audit_log () {
- var audit_log = "/var/log/dirsrv/" + server_id + "/audit"; // TODO - get actual log location from config
- var lines = $("#auditlog-lines").val();
- var logging = cockpit.spawn(["tail", "-" + lines, audit_log],
- { "superuser": "try" }).done(function(data) {
- $("#auditlog-area").text(data);
- });
-}
-
-function refresh_auditfail_log () {
- var auditfail_log = "/var/log/dirsrv/" + server_id + "/auditfail"; // TODO - get actual log location from config
- var lines = $("#auditfaillog-lines").val();
- var logging = cockpit.spawn(["tail", "-" + lines, auditfail_log],
- { "superuser": "try" }).done(function(data) {
- $("#auditfaillog-area").text(data);
- });
-}
-
-function refresh_errors_log () {
- var errors_log = "/var/log/dirsrv/" + server_id + "/errors"; // TODO - get actual log location from config
- var lines = $("#errorslog-lines").val();
- var sev_level = $("#errorslog-sev-level").val();
- var logging = cockpit.spawn(["tail", "-" + lines, errors_log],
- { "superuser": "try" }).done(function(data) {
- if (sev_level != "Everything"){
- // Filter Data
- var lines = data.split('\n');
- var new_data = "";
- for (var i = 0; i < lines.length; i++){
- var line = "";
- if (sev_level == "Error Messages"){
- for (var lev = 0; lev < sev_all_errs.length; lev++) {
- if (lines[i].indexOf(sev_all_errs[lev]) != -1){
- line = lines[i] + "\n";
- }
- }
- } else if (sev_level == "Info Messages"){
- for (var lev = 0; lev < sev_all_info.length; lev++) {
- if (lines[i].indexOf(sev_all_info[lev]) != -1){
- line = lines[i] + "\n";
- }
- }
- } else if (lines[i].indexOf(sev_levels[sev_level]) != -1){
- line = lines[i] + "\n";
- }
- // Add the filtered line to new data
- new_data += line;
- }
- data = new_data;
- }
- $("#errorslog-area").text(data);
- });
-}
-
-
-$(document).ready( function() {
- $("#monitor-content").load("monitor.html", function () {
- $('#monitor-db-tree').jstree({
- "plugins": [ "contextmenu", "wholerow" ],
- });
-
- $("#monitor-server-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- $("#monitor-server-page").show();
- });
-
- $("#monitor-db-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
-
- // TODO - NDN cache prior to 1.4.0 is duplicated under each suffix/backend monitor -
- // so we need to bring it forward to the global database stats here
- var db_hitratio = '99';
- var ndn_hitratio = '83';
- var ndn_maxsize = '25165824';
- var ndn_cursize = '19891200';
- gen_ratio_chart(db_hitratio, '#monitor-db-cache-hitratio-chart');
- gen_ratio_chart(ndn_hitratio, '#monitor-ndn-cache-hitratio-chart');
- gen_util_chart(ndn_cursize, ndn_maxsize, ndn_hitratio, '#monitor-ndn-cache-util-chart');
-
- $("#monitor-db-page").show();
- });
-
-
- $("#monitor-snmp-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- $("#monitor-snmp-page").show();
- });
-
- $("#monitor-repl-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- $("#monitor-repl-page").show();
- });
-
- $("#monitor-log-access-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- refresh_access_log();
- $("#monitor-log-access-page").show();
- });
- $("#monitor-log-audit-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- refresh_audit_log();
- $("#monitor-log-audit-page").show();
- });
- $("#monitor-log-auditfail-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- refresh_auditfail_log()
- $("#monitor-log-auditfail-page").show();
- });
- $("#monitor-log-errors-btn").on("click", function() {
- $(".all-pages").hide();
- $("#monitor-content").show();
- refresh_errors_log();
- $("#monitor-log-errors-page").show();
- });
-
- $("#accesslog-refresh-btn").on('click', function () {
- refresh_access_log();
- });
- $("#auditlog-refresh-btn").on('click', function () {
- refresh_audit_log();
- });
- $("#auditfaillog-refresh-btn").on('click', function () {
- refresh_auditfail_log();
- });
- $("#errorslog-refresh-btn").on('click', function () {
- refresh_errors_log();
- });
-
- $('#monitor-db-tree').on("changed.jstree", function (e, data) {
- var tree_node = data.selected;
- if (tree_node == "monitor-db-main") {
-
- // TODO - NDN cache prior to 1.4.0 is duplicated under each suffix/backend monitor -
- // so we need to bring it forward to the global database stats here
- var db_hitratio = '99';
- var ndn_hitratio = '83';
- var ndn_maxsize = '25165824';
- var ndn_cursize = '19891200';
-
- gen_ratio_chart(db_hitratio, '#monitor-db-cache-hitratio-chart');
- gen_ratio_chart(ndn_hitratio, '#monitor-ndn-cache-hitratio-chart');
- gen_util_chart(ndn_cursize, ndn_maxsize, ndn_hitratio, '#monitor-ndn-cache-util-chart');
- $("#monitor-suffix-page").hide();
- $("#db-content").show();
- } else if (tree_node[0].startsWith("monitor-suffix-")) {
- /*
- * Gather and set the Suffix info
- */
- var monitor_suffix = tree_node[0].replace("monitor-suffix-", "");
- $("#monitor-suffix-header").html("<b>" + monitor_suffix + "</b>");
-
- // TODO - get the monitor info. For now uses DEMO values for the charts
- var entry_hitratio = '96';
- var entry_maxsize = '512000';
- var entry_cursize = '395000';
- var dn_hitratio = '89';
- var dn_maxsize = '51200';
- var dn_cursize = '51200';
-
- // Generate the donut charts
- gen_ratio_chart(entry_hitratio, '#monitor-entry-cache-hitratio-chart');
- gen_util_chart(entry_cursize, entry_maxsize, entry_hitratio, '#monitor-entry-cache-util-chart');
- gen_ratio_chart(dn_hitratio, '#monitor-dn-cache-hitratio-chart');
- gen_util_chart(dn_cursize, dn_maxsize, dn_hitratio, '#monitor-dn-cache-util-chart');
- $("#db-content").hide();
- $("#monitor-suffix-page").show();
- }
- });
-
- var monitor_conn_table = $('#monitor-conn-table').DataTable( {
- "paging": true,
- "bAutoWidth": false,
- "searching": false,
- "dom": '<"pull-left"f><"pull-right"l>tip',
- "lengthChange": false,
- "lengthMenu": [ 10, 25, 50, 100],
- "language": {
- "emptyTable": "No active connections",
- "search": "Search Connections"
- }
- });
- var monitor_index_table = $('#monitor-index-table').DataTable( {
- "paging": true,
- "bAutoWidth": false,
- "dom": '<"pull-left"f><"pull-right"l>tip',
- "lengthMenu": [ 10, 25, 50, 100],
- "language": {
- "emptyTable": "No Attribute Indexes",
- "search": "Search Indexes"
- }
- });
-
- $.fn.dataTable.moment( 'HH:mm:ss' );
- var monitor_repl_table = $('#monitor-repl-table').DataTable( {
- "paging": true,
- "bAutoWidth": false,
- "dom": '<"pull-left"f><"pull-right"l>tip',
- "lengthMenu": [ 10, 25, 50, 100],
- "language": {
- "emptyTable": "No Replication Agreements",
- "search": "Search"
- }
- });
-
- var monitor_winsync_table = $('#monitor-winsync-table').DataTable( {
- "paging": true,
- "bAutoWidth": false,
- "dom": '<"pull-left"f><"pull-right"l>tip',
- "lengthMenu": [ 10, 25, 50, 100],
- "language": {
- "emptyTable": "No Winsync Agreements",
- "search": "Search"
- }
- });
-
- // The continuous log refresh intervals
- $("#accesslog-cont-refresh").change(function() {
- if(this.checked) {
- accesslog_cont_refresh = setInterval(refresh_access_log, 1000);
- } else {
- clearInterval(accesslog_cont_refresh);
- }
- });
-
- $("#auditlog-cont-refresh").change(function() {
- if(this.checked) {
- auditlog_cont_refresh = setInterval(refresh_audit_log, 1000);
- } else {
- clearInterval(auditlog_cont_refresh);
- }
- });
-
- $("#auditfaillog-cont-refresh").change(function() {
- if(this.checked) {
- auditfaillog_cont_refresh = setInterval(refresh_auditfail_log, 1000);
- } else {
- clearInterval(auditfaillog_cont_refresh);
- }
- });
-
- $("#errorslog-cont-refresh").change(function() {
- if(this.checked) {
- errorslog_cont_refresh = setInterval(refresh_errors_log, 1000);
- } else {
- clearInterval(errorslog_cont_refresh);
- }
- });
-
- // Refresh page after changing severity level
- $("#errorslog-sev-level").on("change", function() {
- refresh_errors_log();
- });
-
- $(document).on('click', '.repl-detail-btn', function(e) {
- e.preventDefault();
- var data = monitor_repl_table.row( $(this).parents('tr') ).data();
- var agmt_name = data[0];
- var agmt_suffix = data[2];
- var agmt_enabled = "off"; // TODO Need to determine this from DS data
- var agmt_status = "";
- if (agmt_enabled == "off") {
- agmt_status = " <font size=\"2\" color=\"red\"><b>(Agreement Disabled)</b></font>";
- }
- // clear_agmt_form();
-
- $("#monitor-agmt-header").html("<b>Replication Agreement Details:</b> " + agmt_name + " " + agmt_status);
-
- // TODO - get agreement details and populate form
- $("#monitor-agmt-form").css('display', 'block');
- });
-
-
- $(document).on('click', '.repl-winsync-detail-btn', function(e) {
- e.preventDefault();
- var data = monitor_repl_table.row( $(this).parents('tr') ).data();
- var agmt_name = data[0];
- var agmt_suffix = data[2];
- var agmt_enabled = "on"; // TODO Need to determine this from DS data
- var agmt_status = "";
- if (agmt_enabled == "off") {
- agmt_status = " <font size=\"2\" color=\"red\"><b>(Agreement Disabled)</b></font>";
- }
- // clear_agmt_form();
-
- $("#repl-winsync-agmt-header").html("<b>Winsync Agreement Details:</b> " + agmt_name + " " + agmt_status);
- // TODO - get agreement details and populate form
- $("#monitor-winsync-agmt-form").css('display', 'block');
- });
-
- // Page is loaded, mark it as so...
- monitor_page_loaded = 1;
- });
-});
diff --git a/src/cockpit/389-console/src/monitor.jsx b/src/cockpit/389-console/src/monitor.jsx
new file mode 100644
index 0000000..ae67f4a
--- /dev/null
+++ b/src/cockpit/389-console/src/monitor.jsx
@@ -0,0 +1,1187 @@
+import cockpit from "cockpit";
+import React from "react";
+import { NotificationController } from "./lib/notifications.jsx";
+import { log_cmd } from "./lib/tools.jsx";
+import {
+ TreeView,
+ Spinner,
+ Row,
+ Col,
+ Icon,
+ ControlLabel
+} from "patternfly-react";
+import PropTypes from "prop-types";
+import SNMPMonitor from "./lib/monitor/snmpMonitor.jsx";
+import ServerMonitor from "./lib/monitor/serverMonitor.jsx";
+import DatabaseMonitor from "./lib/monitor/dbMonitor.jsx";
+import SuffixMonitor from "./lib/monitor/suffixMonitor.jsx";
+import ChainingMonitor from "./lib/monitor/chainingMonitor.jsx";
+import AccessLogMonitor from "./lib/monitor/accesslog.jsx";
+import AuditLogMonitor from "./lib/monitor/auditlog.jsx";
+import AuditFailLogMonitor from "./lib/monitor/auditfaillog.jsx";
+import ErrorLogMonitor from "./lib/monitor/errorlog.jsx";
+import ReplMonitor from "./lib/monitor/replMonitor.jsx";
+import "./css/ds.css";
+
+const treeViewContainerStyles = {
+ width: '295px',
+};
+
+export class Monitor extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ nodes: [],
+ node_name: "",
+ node_text: "",
+ node_type: "",
+ loaded: false,
+ snmpData: {},
+ ldbmData: {},
+ serverData: {},
+ showLoading: false,
+ loadingMsg: "",
+ notifications: [],
+ // Suffix
+ suffixLoading: false,
+ serverLoading: false,
+ ldbmLoading: false,
+ snmpLoading: false,
+ chainingLoading: false,
+ // replication
+ replLoading: false,
+ replInitLoaded: false,
+ replSuffix: "",
+ replRole: "",
+ replRid: "",
+ replicatedSuffixes: [],
+ // Access log
+ accesslogLocation: "",
+ accesslogData: "",
+ accessReloading: false,
+ accesslog_cont_refresh: "",
+ accessRefreshing: false,
+ accessLines: "50",
+ // Audit log
+ auditlogLocation: "",
+ auditlogData: "",
+ auditReloading: false,
+ auditlog_cont_refresh: "",
+ auditRefreshing: false,
+ auditLines: "50",
+ // Audit Fail log
+ auditfaillogLocation: "",
+ auditfaillogData: "",
+ auditfailReloading: false,
+ auditfaillog_cont_refresh: "",
+ auditfailRefreshing: false,
+ auditfailLines: "50",
+ // Error log
+ errorlogLocation: "",
+ errorlogData: "",
+ errorReloading: false,
+ errorlog_cont_refresh: "",
+ errorRefreshing: false,
+ errorSevLevel: "Everything",
+ errorLines: "50",
+ };
+
+ // Build the log severity sev_levels
+ let sev_emerg = " - EMERG - ";
+ let sev_crit = " - CRIT - ";
+ let sev_alert = " - ALERT - ";
+ let sev_err = " - ERR - ";
+ let sev_warn = " - WARN - ";
+ let sev_notice = " - NOTICE - ";
+ let sev_info = " - INFO - ";
+ let sev_debug = " - DEBUG - ";
+ this.sev_levels = {
+ "Emergency": sev_emerg,
+ "Critical": sev_crit,
+ "Alert": sev_alert,
+ "Error": sev_err,
+ "Warning": sev_warn,
+ "Notice": sev_notice,
+ "Info": sev_info,
+ "Debug": sev_debug
+ };
+ this.sev_all_errs = [sev_emerg, sev_crit, sev_alert, sev_err];
+ this.sev_all_info = [sev_warn, sev_notice, sev_info, sev_debug];
+
+ // Bindings
+ this.addNotification = this.addNotification.bind(this);
+ this.removeNotification = this.removeNotification.bind(this);
+ this.loadSuffixTree = this.loadSuffixTree.bind(this);
+ this.update_tree_nodes = this.update_tree_nodes.bind(this);
+ this.selectNode = this.selectNode.bind(this);
+ this.loadMonitorSuffix = this.loadMonitorSuffix.bind(this);
+ this.loadMonitorLDBM = this.loadMonitorLDBM.bind(this);
+ this.reloadLDBM = this.reloadLDBM.bind(this);
+ this.loadMonitorSNMP = this.loadMonitorSNMP.bind(this);
+ this.reloadSNMP = this.reloadSNMP.bind(this);
+ this.loadMonitorServer = this.loadMonitorServer.bind(this);
+ this.reloadServer = this.reloadServer.bind(this);
+ this.loadMonitorChaining = this.loadMonitorChaining.bind(this);
+ // Replication
+ this.loadMonitorReplication = this.loadMonitorReplication.bind(this);
+ this.loadCleanTasks = this.loadCleanTasks.bind(this);
+ this.loadAbortTasks = this.loadAbortTasks.bind(this);
+ this.loadReplicatedSuffixes = this.loadReplicatedSuffixes.bind(this);
+ this.loadWinsyncAgmts = this.loadWinsyncAgmts.bind(this);
+ this.replSuffixChange = this.replSuffixChange.bind(this);
+ this.reloadReplAgmts = this.reloadReplAgmts.bind(this);
+ this.reloadReplWinsyncAgmts = this.reloadReplWinsyncAgmts.bind(this);
+ // Logging
+ this.loadMonitor = this.loadMonitor.bind(this);
+ this.refreshAccessLog = this.refreshAccessLog.bind(this);
+ this.refreshAuditLog = this.refreshAuditLog.bind(this);
+ this.refreshAuditFailLog = this.refreshAuditFailLog.bind(this);
+ this.refreshErrorLog = this.refreshErrorLog.bind(this);
+ this.handleAccessChange = this.handleAccessChange.bind(this);
+ this.handleAuditChange = this.handleAuditChange.bind(this);
+ this.handleAuditFailChange = this.handleAuditFailChange.bind(this);
+ this.handleErrorChange = this.handleErrorChange.bind(this);
+ this.accessRefreshCont = this.accessRefreshCont.bind(this);
+ this.auditRefreshCont = this.auditRefreshCont.bind(this);
+ this.auditFailRefreshCont = this.auditFailRefreshCont.bind(this);
+ this.errorRefreshCont = this.errorRefreshCont.bind(this);
+ this.handleSevChange = this.handleSevChange.bind(this);
+ }
+
+ componentDidMount() {
+ this.loadMonitor();
+ }
+
+ componentDidUpdate(prevProps) {
+ if (this.props.serverId !== prevProps.serverId) {
+ this.loadSuffixTree(false);
+ }
+ }
+
+ addNotification(type, message, timerdelay, persistent) {
+ this.setState(prevState => ({
+ notifications: [
+ ...prevState.notifications,
+ {
+ key: prevState.notifications.length + 1,
+ type: type,
+ persistent: persistent,
+ timerdelay: timerdelay,
+ message: message,
+ }
+ ]
+ }));
+ }
+
+ removeNotification(notificationToRemove) {
+ this.setState({
+ notifications: this.state.notifications.filter(
+ notification => notificationToRemove.key !== notification.key
+ )
+ });
+ }
+
+ loadSuffixTree(fullReset) {
+ const cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "backend", "get-tree",
+ ];
+ log_cmd("getTree", "Start building the suffix tree", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let treeData = JSON.parse(content);
+ let basicData = [
+ {
+ text: "Database",
+ selectable: true,
+ selected: true,
+ icon: "fa fa-database",
+ state: {"expanded": true},
+ id: "database-monitor",
+ type: "database",
+ nodes: []
+ },
+ {
+ text: "Logging",
+ icon: "pficon-catalog",
+ selectable: false,
+ id: "log-monitor",
+ nodes: [
+ {
+ text: "Access Log",
+ icon: "glyphicon glyphicon-book",
+ selectable: true,
+ id: "access-log-monitor",
+ type: "log",
+ },
+ {
+ text: "Audit Log",
+ icon: "glyphicon glyphicon-book",
+ selectable: true,
+ id: "audit-log-monitor",
+ type: "log",
+ },
+ {
+ text: "Audit Failure Log",
+ icon: "glyphicon glyphicon-book",
+ selectable: true,
+ id: "auditfail-log-monitor",
+ type: "log",
+ },
+ {
+ text: "Errors Log",
+ icon: "glyphicon glyphicon-book",
+ selectable: true,
+ id: "error-log-monitor",
+ type: "log",
+ },
+ ]
+ },
+ {
+ text: "Replication",
+ selectable: true,
+ icon: "pficon-topology",
+ id: "replication-monitor",
+ type: "replication",
+ },
+ {
+ text: "Server Statistics",
+ icon: "pficon-server",
+ selectable: true,
+ id: "server-monitor",
+ type: "server",
+ },
+ {
+ text: "SNMP Counters",
+ icon: "glyphicon glyphicon-list-alt",
+ selectable: true,
+ id: "snmp-monitor",
+ type: "snmp",
+ },
+
+ ];
+ let current_node = this.state.node_name;
+ let type = this.state.node_type;
+ if (fullReset) {
+ current_node = "database-monitor";
+ type = "database";
+ }
+ basicData[0].nodes = treeData;
+ this.setState(() => ({
+ nodes: basicData,
+ node_name: current_node,
+ node_type: type,
+ }), this.update_tree_nodes);
+ });
+ }
+
+ selectNode(selectedNode) {
+ this.setState({
+ showLoading: true
+ });
+
+ if (selectedNode.id == "database-monitor" ||
+ selectedNode.id == "server-monitor" ||
+ selectedNode.id == "snmp-monitor") {
+ // Nothing special to do, these configurations have already been loaded
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ bename: "",
+ };
+ });
+ } else if (selectedNode.id == "access-log-monitor") {
+ this.refreshAccessLog();
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ };
+ });
+ } else if (selectedNode.id == "audit-log-monitor") {
+ this.refreshAuditLog();
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ };
+ });
+ } else if (selectedNode.id == "auditfail-log-monitor") {
+ this.refreshAuditFailLog();
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ };
+ });
+ } else if (selectedNode.id == "error-log-monitor") {
+ this.refreshErrorLog();
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ };
+ });
+ } else if (selectedNode.id == "replication-monitor") {
+ if (!this.state.replInitLoaded) {
+ this.loadMonitorReplication();
+ }
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ };
+ });
+ } else {
+ if (selectedNode.id in this.state) {
+ // This suffix is already cached, but it might be incomplete...
+ if (selectedNode.type == "dblink" && this.state.nsaddcount === undefined) {
+ this.loadMonitorChaining(selectedNode.id);
+ } else if (selectedNode.type != "dblink" && this.state.entrycachehitratio === undefined) {
+ this.loadMonitorSuffix(selectedNode.id);
+ }
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ node_type: selectedNode.type,
+ bename: selectedNode.be,
+ };
+ });
+ } else {
+ // Load this suffix (db, chaining & replication)
+ if (selectedNode.type == "dblink") {
+ // Chaining
+ this.loadMonitorChaining(selectedNode.id);
+ } else {
+ // Suffix
+ this.loadMonitorSuffix(selectedNode.id);
+ }
+ this.setState(prevState => {
+ return {
+ nodes: this.nodeSelector(prevState.nodes, selectedNode),
+ node_name: selectedNode.id,
+ node_text: selectedNode.text,
+ node_type: selectedNode.type,
+ bename: selectedNode.be,
+ };
+ });
+ }
+ }
+ }
+
+ nodeSelector(nodes, targetNode) {
+ return nodes.map(node => {
+ if (node.nodes) {
+ return {
+ ...node,
+ nodes: this.nodeSelector(node.nodes, targetNode),
+ selected: node.id === targetNode.id ? !node.selected : false
+ };
+ } else if (node.id === targetNode.id) {
+ return { ...node, selected: !node.selected };
+ } else if (node.id !== targetNode.id && node.selected) {
+ return { ...node, selected: false };
+ } else {
+ return node;
+ }
+ });
+ }
+
+ update_tree_nodes() {
+ // Set title to the text value of each suffix node. We need to do this
+ // so we can read long suffixes in the UI tree div
+ let elements = document.getElementsByClassName('treeitem-row');
+ for (let el of elements) {
+ el.setAttribute('title', el.innerText);
+ }
+ this.setState({
+ loaded: true
+ });
+ }
+
+ loadMonitor() {
+ // Load the following componets in a chained fashion:
+ // - log file locations
+ // - LDBM
+ // - Server stats
+ // - SNMP
+ // - Finally load the "tree"
+ //
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "config", "get", "nsslapd-auditlog", "nsslapd-accesslog", "nsslapd-errorlog", "nsslapd-auditfaillog"
+ ];
+ log_cmd("loadLogLocations", "Get log locations", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ accesslogLocation: config.attrs['nsslapd-accesslog'][0],
+ auditlogLocation: config.attrs['nsslapd-auditlog'][0],
+ auditfaillogLocation: config.attrs['nsslapd-auditfaillog'][0],
+ errorlogLocation: config.attrs['nsslapd-errorlog'][0],
+ });
+ }, this.loadReplicatedSuffixes());
+ }
+
+ loadReplicatedSuffixes() {
+ // Load replicated suffix to populate the dropdown select list
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "replication", "list"
+ ];
+ log_cmd("loadReplicatedSuffixes", "Load replication suffixes", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ let replSuffix = "";
+ if (config.items.length > 0) {
+ replSuffix = config.items[0];
+ }
+ this.setState({
+ replicatedSuffixes: config.items,
+ replSuffix: replSuffix,
+ });
+ }, this.loadMonitorLDBM());
+ }
+
+ loadMonitorLDBM() {
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "ldbm"
+ ];
+ log_cmd("loadMonitorLDBM", "Load database monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ ldbmData: config.attrs
+ });
+ }, this.loadMonitorServer());
+ }
+
+ reloadLDBM() {
+ this.setState({
+ ldbmLoading: true
+ });
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "ldbm"
+ ];
+ log_cmd("reloadLDBM", "Load database monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ ldbmLoading: false,
+ ldbmData: config.attrs
+ });
+ });
+ }
+
+ loadMonitorServer() {
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "server"
+ ];
+ log_cmd("loadMonitorServer", "Load server monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ serverData: config.attrs
+ });
+ }, this.loadMonitorSNMP());
+ }
+
+ reloadServer() {
+ this.setState({
+ serverLoading: true
+ });
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "server"
+ ];
+ log_cmd("reloadServer", "Load server monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ serverLoading: false,
+ serverData: config.attrs
+ });
+ });
+ }
+
+ loadMonitorSNMP() {
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "snmp"
+ ];
+ log_cmd("loadMonitorSNMP", "Load snmp monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ snmpData: config.attrs,
+ }, this.loadSuffixTree(true));
+ });
+ }
+
+ reloadSNMP() {
+ this.setState({
+ snmpLoading: true
+ });
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "snmp"
+ ];
+ log_cmd("reloadSNMP", "Load snmp monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ snmpLoading: false,
+ snmpData: config.attrs,
+ });
+ });
+ }
+
+ loadMonitorChaining(suffix) {
+ this.setState({
+ chainingLoading: true
+ });
+
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "chaining", suffix
+ ];
+ log_cmd("loadMonitorChaining", "Load suffix monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [suffix]: {
+ ...this.state[suffix],
+ chainingData: config.attrs,
+ },
+ chainingLoading: false,
+ });
+ })
+ .fail(() => {
+ // Notification of failure (could only be server down)
+ this.setState({
+ chainingLoading: false,
+ });
+ });
+ }
+
+ loadMonitorSuffix(suffix) {
+ this.setState({
+ suffixLoading: true
+ });
+
+ let cmd = [
+ "dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "monitor", "backend", suffix
+ ];
+ log_cmd("loadMonitorSuffix", "Load suffix monitor", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [suffix]: {
+ ...this.state[suffix],
+ suffixData: config.attrs,
+ },
+ suffixLoading: false,
+ });
+ })
+ .fail(() => {
+ // Notification of failure (could only be server down)
+ this.setState({
+ suffixLoading: false,
+ });
+ });
+ }
+
+ loadCleanTasks() {
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "repl-tasks", "list-cleanruv-tasks", "--suffix=" + this.state.replSuffix];
+ log_cmd("loadCleanTasks", "Load clean tasks", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [this.state.replSuffix]: {
+ ...this.state[this.state.replSuffix],
+ cleanTasks: config.items,
+ },
+ }, this.loadAbortTasks());
+ })
+ .fail(() => {
+ // Notification of failure (could only be server down)
+ this.setState({
+ replLoading: false,
+ });
+ });
+ }
+
+ loadAbortTasks() {
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "repl-tasks", "list-abortruv-tasks", "--suffix=" + this.state.replSuffix];
+ log_cmd("loadAbortCleanTasks", "Load abort tasks", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [this.state.replSuffix]: {
+ ...this.state[this.state.replSuffix],
+ abortTasks: config.items,
+ },
+ }, this.setState(
+ {
+ replLoading: false,
+ replInitLoaded: true
+ }));
+ })
+ .fail(() => {
+ // Notification of failure (could only be server down)
+ this.setState({
+ replLoading: false,
+ });
+ });
+ }
+
+ loadWinsyncAgmts() {
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "replication", "winsync-status", "--suffix=" + this.state.replSuffix];
+ log_cmd("loadWinsyncAgmts", "Load winsync agmt status", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [this.state.replSuffix]: {
+ ...this.state[this.state.replSuffix],
+ replWinsyncAgmts: config.items,
+ },
+ }, this.loadCleanTasks());
+ })
+ .fail(() => {
+ // Notification of failure (could only be server down)
+ this.setState({
+ replLoading: false,
+ });
+ });
+ }
+
+ loadMonitorReplication() {
+ let replSuffix = this.state.replSuffix;
+ if (replSuffix != "") {
+ this.setState({
+ replLoading: true
+ });
+
+ // Now load the agmts
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "replication", "status", "--suffix=" + replSuffix];
+ log_cmd("loadMonitorReplication", "Load replication agmts", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [replSuffix]: {
+ ...this.state[replSuffix],
+ replAgmts: config.items,
+ abortTasks: [],
+ cleanTasks: [],
+ replWinsyncAgmts: [],
+ },
+ }, this.loadWinsyncAgmts());
+ })
+ .fail(() => {
+ // Notification of failure (could only be server down)
+ this.setState({
+ replLoading: false,
+ });
+ });
+ }
+ }
+
+ reloadReplAgmts() {
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "replication", "status", "--suffix=" + this.state.replSuffix];
+ log_cmd("reloadReplAgmts", "Load replication agmts", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [this.state.replSuffix]: {
+ ...this.state[this.state.replSuffix],
+ replAgmts: config.items,
+ },
+ });
+ });
+ }
+
+ reloadReplWinsyncAgmts() {
+ let cmd = ["dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket",
+ "replication", "winsync-status", "--suffix=" + this.state.replSuffix];
+ log_cmd("reloadReplWinsyncAgmts", "Load winysnc agmts", cmd);
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ let config = JSON.parse(content);
+ this.setState({
+ [this.state.replSuffix]: {
+ ...this.state[this.state.replSuffix],
+ replWinsyncAgmts: config.items,
+ },
+ });
+ });
+ }
+
+ refreshAccessLog () {
+ this.setState({
+ accessReloading: true
+ });
+ let cmd = ["tail", "-" + this.state.accessLines, this.state.accesslogLocation];
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.setState(() => ({
+ accesslogData: content,
+ accessReloading: false
+ }));
+ });
+ }
+
+ refreshAuditLog () {
+ this.setState({
+ auditReloading: true
+ });
+ let cmd = ["tail", "-" + this.state.auditLines, this.state.auditlogLocation];
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.setState(() => ({
+ auditlogData: content,
+ auditReloading: false
+ }));
+ });
+ }
+
+ refreshAuditFailLog () {
+ this.setState({
+ auditfailReloading: true
+ });
+ let cmd = ["tail", "-" + this.state.auditfailLines, this.state.auditfaillogLocation];
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(content => {
+ this.setState(() => ({
+ auditfaillogData: content,
+ auditfailReloading: false
+ }));
+ });
+ }
+
+ refreshErrorLog () {
+ this.setState({
+ errorReloading: true
+ });
+
+ let cmd = ["tail", "-" + this.state.errorLines, this.state.errorlogLocation];
+ cockpit
+ .spawn(cmd, { superuser: true, err: "message" })
+ .done(data => {
+ if (this.state.errorSevLevel != "Everything") {
+ // Filter Data
+ let lines = data.split('\n');
+ let new_data = "";
+ for (let i = 0; i < lines.length; i++) {
+ let line = "";
+ if (this.state.errorSevLevel == "Error Messages") {
+ for (let lev of this.sev_all_errs) {
+ if (lines[i].indexOf(lev) != -1) {
+ line = lines[i] + "\n";
+ }
+ }
+ } else if (this.state.errorSevLevel == "Info Messages") {
+ for (let lev of this.sev_all_info) {
+ if (lines[i].indexOf(lev) != -1) {
+ line = lines[i] + "\n";
+ }
+ }
+ } else if (lines[i].indexOf(this.sev_levels[this.state.errorSevLevel]) != -1) {
+ line = lines[i] + "\n";
+ }
+ // Add the filtered line to new data
+ new_data += line;
+ }
+ data = new_data;
+ }
+
+ this.setState(() => ({
+ errorlogData: data,
+ errorReloading: false
+ }));
+ });
+ }
+
+ accessRefreshCont(e) {
+ if (e.target.checked) {
+ this.state.accesslog_cont_refresh = setInterval(this.refreshAccessLog, 2000);
+ } else {
+ clearInterval(this.state.accesslog_cont_refresh);
+ }
+ this.setState({
+ accessRefreshing: e.target.checked,
+ });
+ }
+
+ auditRefreshCont(e) {
+ if (e.target.checked) {
+ this.state.auditlog_cont_refresh = setInterval(this.refreshAuditLog, 2000);
+ } else {
+ clearInterval(this.state.auditlog_cont_refresh);
+ }
+ this.setState({
+ auditRefreshing: e.target.checked,
+ });
+ }
+
+ auditFailRefreshCont(e) {
+ if (e.target.checked) {
+ this.state.auditfaillog_cont_refresh = setInterval(this.refreshAuditFailLog, 2000);
+ } else {
+ clearInterval(this.state.auditfaillog_cont_refresh);
+ }
+ this.setState({
+ auditfailRefreshing: e.target.checked,
+ });
+ }
+
+ errorRefreshCont(e) {
+ if (e.target.checked) {
+ this.state.errorlog_cont_refresh = setInterval(this.refreshErrorLog, 2000);
+ } else {
+ clearInterval(this.state.errorlog_cont_refresh);
+ }
+ this.setState({
+ errorRefreshing: e.target.checked,
+ });
+ }
+
+ handleAccessChange(e) {
+ let value = e.target.value;
+ this.setState(() => (
+ {
+ accessLines: value
+ }
+ ), this.refreshAccessLog);
+ }
+
+ handleAuditChange(e) {
+ let value = e.target.value;
+ this.setState(() => (
+ {
+ auditLines: value
+ }
+ ), this.refreshAuditLog);
+ }
+
+ handleAuditFailChange(e) {
+ let value = e.target.value;
+ this.setState(() => (
+ {
+ auditfailLines: value
+ }
+ ), this.refreshAuditFailLog);
+ }
+
+ handleErrorChange(e) {
+ let value = e.target.value;
+ this.setState(() => (
+ {
+ errorLines: value
+ }
+ ), this.refreshErrorLog);
+ }
+
+ handleSevChange(e) {
+ const value = e.target.value;
+
+ this.setState({
+ errorSevLevel: value,
+ }, this.refreshErrorLog);
+ }
+
+ replSuffixChange(e) {
+ let value = e.target.value;
+ this.setState(() => (
+ {
+ replSuffix: value,
+ replLoading: true
+ }
+ ), this.loadMonitorReplication);
+ }
+
+ render() {
+ const { nodes } = this.state;
+ let monitorPage = "";
+ let monitor_element = "";
+
+ if (this.state.loaded) {
+ if (this.state.node_name == "database-monitor" || this.state.node_name == "") {
+ if (this.state.ldbmLoading) {
+ monitor_element =
+ <div className="ds-loading-spinner ds-center">
+ <p />
+ <h4><b>Loading database monitor information ...</b></h4>
+ <Spinner loading size="md" />
+ </div>;
+ } else {
+ monitor_element =
+ <DatabaseMonitor
+ data={this.state.ldbmData}
+ reload={this.reloadLDBM}
+ />;
+ }
+ } else if (this.state.node_name == "server-monitor") {
+ if (this.state.serverLoading) {
+ monitor_element =
+ <div className="ds-loading-spinner ds-center">
+ <p />
+ <h4><b>Loading server monitor information ...</b></h4>
+ <Spinner loading size="md" />
+ </div>;
+ } else {
+ monitor_element =
+ <ServerMonitor
+ data={this.state.serverData}
+ reload={this.reloadServer}
+ serverId={this.props.serverId}
+ />;
+ }
+ } else if (this.state.node_name == "snmp-monitor") {
+ if (this.state.snmpLoading) {
+ monitor_element =
+ <div className="ds-loading-spinner ds-center">
+ <p />
+ <h4><b>Loading SNMP monitor information ...</b></h4>
+ <Spinner loading size="md" />
+ </div>;
+ } else {
+ monitor_element =
+ <SNMPMonitor
+ data={this.state.snmpData}
+ reload={this.reloadSNMP}
+ />;
+ }
+ } else if (this.state.node_name == "access-log-monitor") {
+ monitor_element =
+ <AccessLogMonitor
+ data={this.state.accesslogData}
+ handleChange={this.handleAccessChange}
+ reload={this.refreshAccessLog}
+ reloading={this.state.accessReloading}
+ refreshing={this.state.accessRefreshing}
+ handleRefresh={this.accessRefreshCont}
+ lines={this.state.accessLines}
+ />;
+ } else if (this.state.node_name == "audit-log-monitor") {
+ monitor_element =
+ <AuditLogMonitor
+ data={this.state.auditlogData}
+ handleChange={this.handleAuditChange}
+ reload={this.refreshAuditLog}
+ reloading={this.state.auditReloading}
+ refreshing={this.state.auditRefreshing}
+ handleRefresh={this.auditRefreshCont}
+ lines={this.state.auditLines}
+ />;
+ } else if (this.state.node_name == "auditfail-log-monitor") {
+ monitor_element =
+ <AuditFailLogMonitor
+ data={this.state.auditfaillogData}
+ handleChange={this.handleAuditFailChange}
+ reload={this.refreshAuditFailLog}
+ reloading={this.state.auditfailReloading}
+ refreshing={this.state.auditfailRefreshing}
+ handleRefresh={this.auditFailRefreshCont}
+ lines={this.state.auditfailLines}
+ />;
+ } else if (this.state.node_name == "error-log-monitor") {
+ monitor_element =
+ <ErrorLogMonitor
+ data={this.state.errorlogData}
+ handleChange={this.handleErrorChange}
+ reload={this.refreshErrorLog}
+ reloading={this.state.errorReloading}
+ refreshing={this.state.errorRefreshing}
+ handleRefresh={this.errorRefreshCont}
+ handleSevLevel={this.handleSevChange}
+ lines={this.state.errorLines}
+ />;
+ } else if (this.state.node_name == "replication-monitor") {
+ if (this.state.replLoading) {
+ monitor_element =
+ <div className="ds-loading-spinner ds-center">
+ <p />
+ <h4>Loading replication monitor information ...</h4>
+ <Spinner loading size="md" />
+ </div>;
+ } else {
+ if (this.state.replicatedSuffixes.length < 1) {
+ monitor_element =
+ <div>
+ <p>There are no suffixes that have been configured for replication</p>
+ </div>;
+ } else {
+ let suffixList = this.state.replicatedSuffixes.map((suffix) =>
+ <option key={suffix} value={suffix}>{suffix}</option>
+ );
+ monitor_element =
+ <div>
+ <Row>
+ <Col sm={12}>
+ <ControlLabel className="ds-header">Replication Monitoring</ControlLabel>
+ <select className="ds-left-indent" defaultValue={this.state.replSuffix} onChange={this.replSuffixChange}>
+ {suffixList}
+ </select>
+ <Icon className="ds-left-margin ds-refresh"
+ type="fa" name="refresh" title="Refresh replication monitor"
+ onClick={() => this.loadMonitorReplication()}
+ />
+ </Col>
+ </Row>
+ <div className="ds-margin-top-med">
+ <ReplMonitor
+ suffix={this.state.replSuffix}
+ serverId={this.props.serverId}
+ data={this.state[this.state.replSuffix]}
+ addNotification={this.addNotification}
+ reloadAgmts={this.reloadReplAgmts}
+ reloadWinsyncAgmts={this.reloadReplWinsyncAgmts}
+ key={this.state.replSuffix}
+ />
+ </div>
+ </div>;
+ }
+ }
+ } else if (this.state.node_name != "") {
+ // suffixes (example)
+ if (this.state.suffixLoading) {
+ monitor_element =
+ <div className="ds-loading-spinner ds-center">
+ <p />
+ <h4>Loading suffix monitor information for <b>{this.state.node_text} ...</b></h4>
+ <Spinner loading size="md" />
+ </div>;
+ } else if (this.state.chainingLoading) {
+ monitor_element =
+ <div className="ds-loading-spinner ds-center">
+ <p />
+ <h4>Loading chaining monitor information for <b>{this.state.node_text} ...</b></h4>
+ <Spinner loading size="md" />
+ </div>;
+ } else {
+ if (this.state.node_type == "dblink") {
+ monitor_element =
+ <ChainingMonitor
+ suffix={this.state.node_text}
+ bename={this.state.bename}
+ reload={this.loadMonitorChaining}
+ data={this.state[this.state.node_text].chainingData}
+ key={this.state.node_text}
+ />;
+ } else {
+ // Suffix
+ monitor_element =
+ <SuffixMonitor
+ suffix={this.state.node_text}
+ bename={this.state.bename}
+ reload={this.loadMonitorSuffix}
+ data={this.state[this.state.node_text].suffixData}
+ key={this.state.node_text}
+ />;
+ }
+ }
+ }
+ monitorPage =
+ <div className="container-fluid">
+ <NotificationController
+ notifications={this.state.notifications}
+ removeNotificationAction={this.removeNotification}
+ />
+ <div className="ds-container">
+ <div>
+ <div className="ds-tree">
+ <div className="tree-view-container" id="db-tree"
+ style={treeViewContainerStyles}>
+ <TreeView
+ nodes={nodes}
+ highlightOnHover
+ highlightOnSelect
+ selectNode={this.selectNode}
+ />
+ </div>
+ </div>
+ </div>
+ <div className="ds-tree-content">
+ {monitor_element}
+ </div>
+ </div>
+ </div>;
+ } else {
+ monitorPage =
+ <div className="ds-loading-spinner ds-center">
+ <p />
+ <h4>Loading monitor information ...</h4>
+ <Spinner loading size="md" />
+ </div>;
+ }
+
+ return (
+ <div>
+ {monitorPage}
+ </div>
+ );
+ }
+}
+
+// Property types and defaults
+
+Monitor.propTypes = {
+ serverId: PropTypes.string
+};
+
+Monitor.defaultProps = {
+ serverId: ""
+};
diff --git a/src/cockpit/389-console/src/plugins.jsx b/src/cockpit/389-console/src/plugins.jsx
index cab8952..ac9f8b7 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -182,7 +182,8 @@ export class Plugins extends React.Component {
})
.fail(err => {
if (err != 0) {
- console.log("pluginList failed", err);
+ let errMsg = JSON.parse(err);
+ console.log("pluginList failed: ", errMsg.desc);
}
this.toggleLoading();
});
@@ -238,12 +239,13 @@ export class Plugins extends React.Component {
this.toggleLoading();
})
.fail(err => {
- if (err.message.indexOf("nothing to set") >= 0) {
+ let errMsg = JSON.parse(err);
+ if (errMsg.desc.indexOf("nothing to set") >= 0) {
nothingToSetErr = true;
} else {
this.addNotification(
"error",
- `${err.message} error during ${data.name} modification`
+ `${errMsg.desc} error during ${data.name} modification`
);
}
this.closePluginModal();
@@ -275,12 +277,13 @@ export class Plugins extends React.Component {
console.info("savePlugin", "Result", content);
})
.fail(err => {
+ let errMsg = JSON.parse(err);
if (
- (err.message.indexOf(
+ (errMsg.desc.indexOf(
"nothing to set"
) >= 0 &&
- nothingToSetErr) ||
- err.message.indexOf("nothing to set") < 0
+ nothingToSetErr) ||
+ errMsg.desc.indexOf("nothing to set") < 0
) {
if (basicPluginSuccess) {
this.addNotification(
@@ -291,7 +294,7 @@ export class Plugins extends React.Component {
}
this.addNotification(
"error",
- `${err.message} error during ${data.name} modification`
+ `${errMsg.desc} error during ${data.name} modification`
);
}
this.toggleLoading();
diff --git a/src/cockpit/389-console/src/replication.html b/src/cockpit/389-console/src/replication.html
index 06a26e8..f68c837 100644
--- a/src/cockpit/389-console/src/replication.html
+++ b/src/cockpit/389-console/src/replication.html
@@ -181,8 +181,6 @@ Winsync Agreements
<div id="repl-winsync" class="all-pages" hidden>
<h3 class="ds-config-header">Windows Synchronization Agreements for <select
class="btn btn-default dropdown" id="select-repl-winsync-suffix">
- <option>dc=example,dc=com</option>
- <option>o=ipaca</option>
</select></h3>
<div class="ds-page-content">
<table id="repl-winsync-agmt-table" class="display ds-repl-table" cellspacing="0" width="100%">
@@ -443,7 +441,7 @@ CleanAllRUV Tasks
</div>
</div>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="agmt-save">Save Agreement</button>
</div>
@@ -530,7 +528,7 @@ CleanAllRUV Tasks
</div>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="winsync-agmt-save">Save Agreement</button>
</div>
@@ -575,7 +573,7 @@ CleanAllRUV Tasks
</div>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="cleanallruv-save">Create Task</button>
</div>
@@ -620,7 +618,7 @@ CleanAllRUV Tasks
</div>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="add-repl-mgr-save">Add Manager</button>
</div>
@@ -645,7 +643,7 @@ CleanAllRUV Tasks
</select>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary" id="select-attr-save">Add Attributes</button>
</div>
@@ -726,7 +724,7 @@ CleanAllRUV Tasks
</div>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="enable-repl-save">Save</button>
</div>
diff --git a/src/cockpit/389-console/src/replication.js b/src/cockpit/389-console/src/replication.js
index 3aa3136..6ef3635 100644
--- a/src/cockpit/389-console/src/replication.js
+++ b/src/cockpit/389-console/src/replication.js
@@ -347,7 +347,7 @@ function get_and_set_repl_agmts () {
function get_and_set_cleanallruv() {
console.log("Loading replication tasks...");
- var cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','repl-tasks', 'list-cleanallruv'];
+ let cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','repl-tasks', 'list-cleanruv-tasks'];
log_cmd('get_and_set_cleanallruv', 'Get the cleanAllRUV tasks', cmd);
cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
var tasks = JSON.parse(data);
@@ -729,7 +729,7 @@ $(document).ready( function() {
$("#replication-content").show();
$("#repl-winsync").show();
});
- $("#repl-cleanallruv-btn").on("click", function() {
+ $("#repl-tasks-btn").on("click", function() {
$(".all-pages").hide();
$("#replication-content").show();
$("#repl-cleanallruv").show();
@@ -1975,7 +1975,7 @@ $(document).ready( function() {
}
log_cmd('#cleanallruv-save (click)', 'Create CleanAllRUV Task', cmd);
cockpit.spawn(cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function() {
- var list_cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','repl-tasks', 'list-cleanallruv'];
+ let list_cmd = [DSCONF, '-j', 'ldapi://%2fvar%2frun%2f' + server_id + '.socket','repl-tasks', 'list-cleanruv-tasks'];
log_cmd('#cleanallruv-save (click)', 'List all the CleanAllRUV tasks', list_cmd);
cockpit.spawn(list_cmd, { superuser: true, "err": "message", "environ": [ENV]}).done(function(data) {
repl_clean_table.clear().draw();
diff --git a/src/cockpit/389-console/src/schema.html b/src/cockpit/389-console/src/schema.html
index 74388e2..b677d5b 100644
--- a/src/cockpit/389-console/src/schema.html
+++ b/src/cockpit/389-console/src/schema.html
@@ -155,7 +155,7 @@
<p><span class="spinner spinner-xs spinner-inline"></span> Processing...<p>
</div>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="save-attr-button">Save</button>
</div>
@@ -245,7 +245,7 @@
<p><span class="spinner spinner-xs spinner-inline"></span> Processing...<p>
</div>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="save-oc-button">Save</button>
</div>
diff --git a/src/cockpit/389-console/src/servers.html b/src/cockpit/389-console/src/servers.html
index 7d3c745..8f40883 100644
--- a/src/cockpit/389-console/src/servers.html
+++ b/src/cockpit/389-console/src/servers.html
@@ -464,8 +464,6 @@
<h3 class="ds-config-header">Local Password Policies </h3>
<label class="ds-config-label-med" for="local-pwp-suffix">Database Suffix</Label> <select
class="btn btn-default dropdown" id="local-pwp-suffix">
- <option>dc=example,dc=com</option>
- <option>o=ipaca</option>
</select>
<div class="ds-page-content">
<table id="passwd-policy-table" class="display ds-repl-table" cellspacing="0" width="100%">
@@ -1054,7 +1052,7 @@
</div>
</form>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="sasl-map-save">Save</button>
</div>
@@ -1264,7 +1262,7 @@
</form>
</div>
</div>
- <div class="modal-footer ds-modal-footer">
+ <div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary" id="local-pwp-save">Save</button>
</div>
diff --git a/src/cockpit/389-console/webpack.config.js b/src/cockpit/389-console/webpack.config.js
index 8c89041..d4ac364 100644
--- a/src/cockpit/389-console/webpack.config.js
+++ b/src/cockpit/389-console/webpack.config.js
@@ -30,8 +30,6 @@ var info = {
"fonts",
"images",
"index.html",
- "monitor.html",
- "monitor.js",
"replication.html",
"replication.js",
"rhds-banner.html",
diff --git a/src/lib389/cli/dsconf b/src/lib389/cli/dsconf
index b22736e..37e6282 100755
--- a/src/lib389/cli/dsconf
+++ b/src/lib389/cli/dsconf
@@ -15,6 +15,8 @@ import logging
import ldap
import sys
import signal
+import json
+import ast
from lib389 import DirSrv
from lib389._constants import DN_CONFIG, DN_DM
from lib389.cli_conf import config as cli_config
@@ -132,10 +134,15 @@ if __name__ == '__main__':
log.info("Command successful.")
except Exception as e:
log.debug(e, exc_info=True)
+ errmsg = str(e)
if args and args.json:
- sys.stderr.write(str(e) + '\n')
+ try:
+ msg = ast.literal_eval(errmsg)
+ except:
+ msg = {'desc': errmsg}
+ sys.stderr.write(json.dumps(msg))
else:
- log.error("Error: %s" % str(e))
+ log.error("Error: %s" % errmsg)
result = False
disconnect_instance(inst)
@@ -143,5 +150,3 @@ if __name__ == '__main__':
# Done!
if result is False:
sys.exit(1)
-
-
diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py
index 6e2538e..a141877 100644
--- a/src/lib389/lib389/_mapped_object.py
+++ b/src/lib389/lib389/_mapped_object.py
@@ -491,6 +491,17 @@ class DSLdapObject(DSLogging):
entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys, serverctrls=self._server_controls, clientctrls=self._client_controls)[0]
return entry.getValuesSet(keys)
+ def get_attrs_vals_utf8(self, keys, use_json=False):
+ self._log.debug("%s get_attrs_vals_utf8(%r)" % (self._dn, keys))
+ if self._instance.state != DIRSRV_STATE_ONLINE:
+ raise ValueError("Invalid state. Cannot get properties on instance that is not ONLINE")
+ entry = self._instance.search_ext_s(self._dn, ldap.SCOPE_BASE, self._object_filter, attrlist=keys, serverctrls=self._server_controls, clientctrls=self._client_controls, escapehatch='i am sure')[0]
+ vset = entry.getValuesSet(keys)
+ r = {}
+ for (k, vo) in vset.items():
+ r[k] = ensure_list_str(vo)
+ return r
+
def get_attr_vals(self, key, use_json=False):
self._log.debug("%s get_attr_vals(%r)" % (self._dn, key))
# We might need to add a state check for NONE dn.
@@ -955,7 +966,7 @@ class DSLdapObjects(DSLogging):
# Filter based on the objectclasses and the basedn
# Based on the selector, we should filter on that too.
# This will yield and & filter for objectClass with as many terms as needed.
- filterstr=_gen_and([
+ filterstr = _gen_and([
self._get_objectclass_filter(),
_gen_or(
# This will yield all combinations of selector to filterattrs.
@@ -1024,5 +1035,3 @@ class DSLdapObjects(DSLogging):
(rdn, properties) = self._validate(rdn, properties)
# Now actually commit the creation req
return co.ensure_state(rdn, properties, self._basedn)
-
-
diff --git a/src/lib389/lib389/agreement.py b/src/lib389/lib389/agreement.py
index 128a607..cea9234 100644
--- a/src/lib389/lib389/agreement.py
+++ b/src/lib389/lib389/agreement.py
@@ -173,8 +173,10 @@ class Agreement(DSLdapObject):
consumer.allocate(args_standalone)
try:
consumer.open()
+ except ldap.INVALID_CREDENTIALS as e:
+ raise(e)
except ldap.LDAPError as e:
- self._instance.log.debug('Connection to consumer ({}:{}) failed, error: {}'.format(host, port, e))
+ self._log.debug('Connection to consumer ({}:{}) failed, error: {}'.format(host, port, e))
return result_msg
# Search for the tombstone RUV entry
@@ -182,7 +184,7 @@ class Agreement(DSLdapObject):
entry = consumer.search_s(suffix, ldap.SCOPE_SUBTREE,
REPLICA_RUV_FILTER, ['nsds50ruv'])
if not entry:
- self.log.error("Failed to retrieve database RUV entry from consumer")
+ self._log.debug("Failed to retrieve database RUV entry from consumer")
else:
elements = ensure_list_str(entry[0].getValues('nsds50ruv'))
for ruv in elements:
@@ -191,8 +193,10 @@ class Agreement(DSLdapObject):
if len(ruv_parts) == 5:
result_msg = ruv_parts[4]
break
+ except ldap.INVALID_CREDENTIALS as e:
+ raise(e)
except ldap.LDAPError as e:
- self._instance.log.debug('Failed to search for the suffix ' +
+ self._log.debug('Failed to search for the suffix ' +
'({}) consumer ({}:{}) failed, error: {}'.format(
suffix, host, port, e))
consumer.close()
@@ -208,26 +212,31 @@ class Agreement(DSLdapObject):
"""
status = "Unknown"
- agmt_maxcsn = self.get_agmt_maxcsn()
- if agmt_maxcsn is not None:
- con_maxcsn = self.get_consumer_maxcsn(binddn=binddn, bindpw=bindpw)
- if con_maxcsn:
- if agmt_maxcsn == con_maxcsn:
- status = "In Synchronization"
- else:
- # Not in sync - attempt to discover the cause
- repl_msg = "Unknown"
- if self.get_attr_val_utf8(AGMT_UPDATE_IN_PROGRESS) == 'TRUE':
- # Replication is on going - this is normal
- repl_msg = "Replication still in progress"
- elif "Can't Contact LDAP" in \
- self.get_attr_val_utf8(AGMT_UPDATE_STATUS):
- # Consumer is down
- repl_msg = "Consumer can not be contacted"
-
- status = ("Not in Synchronization: supplier " +
- "(%s) consumer (%s) Reason(%s)" %
- (agmt_maxcsn, con_maxcsn, repl_msg))
+ try:
+ agmt_maxcsn = self.get_agmt_maxcsn()
+ if agmt_maxcsn is not None:
+ con_maxcsn = self.get_consumer_maxcsn(binddn=binddn, bindpw=bindpw)
+ if con_maxcsn:
+ if agmt_maxcsn == con_maxcsn:
+ status = "In Synchronization"
+ else:
+ # Not in sync - attempt to discover the cause
+ repl_msg = "Unknown"
+ if self.get_attr_val_utf8_l(AGMT_UPDATE_IN_PROGRESS) == 'true':
+ # Replication is on going - this is normal
+ repl_msg = "Replication still in progress"
+ elif "can't contact ldap" in \
+ self.get_attr_val_utf8_l(AGMT_UPDATE_STATUS):
+ # Consumer is down
+ repl_msg = "Consumer can not be contacted"
+
+ status = ("Not in Synchronization: supplier " +
+ "(%s) consumer (%s) Reason(%s)" %
+ (agmt_maxcsn, con_maxcsn, repl_msg))
+ except ldap.INVALID_CREDENTIALS as e:
+ raise(e)
+ except ldap.LDAPError as e:
+ raise ValueError(str(e))
return status
def get_lag_time(self, suffix, agmt_name, binddn=None, bindpw=None):
@@ -243,15 +252,20 @@ class Agreement(DSLdapObject):
:returns: A time-formated string of the the replication lag (HH:MM:SS).
:raises: ValueError - if unable to get consumer's maxcsn
"""
- agmt_time = 0
- agmt_maxcsn = self.get_agmt_maxcsn()
- con_maxcsn = self.get_consumer_maxcsn(binddn=binddn, bindpw=bindpw)
+
+ try:
+ agmt_maxcsn = self.get_agmt_maxcsn()
+ con_maxcsn = self.get_consumer_maxcsn(binddn=binddn, bindpw=bindpw)
+ except ldap.LDAPError as e:
+ raise ValueError("Unable to get lag time: " + str(e))
+
if con_maxcsn is None:
raise ValueError("Unable to get consumer's max csn")
- if con_maxcsn == "Unavailable":
+ if con_maxcsn.lower() == "unavailable":
return con_maxcsn
# Extract the csn timstamps and compare them
+ agmt_time = 0
match = Agreement.csnre.match(agmt_maxcsn)
if match:
agmt_time = int(match.group(1), 16)
@@ -292,6 +306,8 @@ class Agreement(DSLdapObject):
if not winsync:
try:
status = self.get_agmt_status(binddn=binddn, bindpw=bindpw)
+ except ldap.INVALID_CREDENTIALS as e:
+ raise(e)
except ValueError as e:
status = str(e)
if just_status:
@@ -305,6 +321,7 @@ class Agreement(DSLdapObject):
agmt_name = ensure_str(status_attrs_dict['cn'][0])
lag_time = self.get_lag_time(suffix, agmt_name, binddn=binddn, bindpw=bindpw)
else:
+ lag_time = "Not available for Winsync agreements"
status = "Not available for Winsync agreements"
# handle the attributes that are not always set in the agreement
@@ -323,16 +340,21 @@ class Agreement(DSLdapObject):
if ensure_str(status_attrs_dict['nsds5replicachangessentsincestartup'][0]) == '':
status_attrs_dict['nsds5replicachangessentsincestartup'] = ['0']
+ consumer = "{}:{}".format(ensure_str(status_attrs_dict['nsds5replicahost'][0]),
+ ensure_str(status_attrs_dict['nsds5replicaport'][0]))
+
# Case sensitive?
if use_json:
- result = {'replica-enabled': ensure_str(status_attrs_dict['nsds5replicaenabled'][0]),
+ result = {
+ 'agmt-name': ensure_str(status_attrs_dict['cn'][0]),
+ 'replica': consumer,
+ 'replica-enabled': ensure_str(status_attrs_dict['nsds5replicaenabled'][0]),
'update-in-progress': ensure_str(status_attrs_dict['nsds5replicaupdateinprogress'][0]),
'last-update-start': ensure_str(status_attrs_dict['nsds5replicalastupdatestart'][0]),
'last-update-end': ensure_str(status_attrs_dict['nsds5replicalastupdateend'][0]),
'number-changes-sent': ensure_str(status_attrs_dict['nsds5replicachangessentsincestartup'][0]),
'number-changes-skipped:': ensure_str(status_attrs_dict['nsds5replicachangesskippedsince'][0]),
'last-update-status': ensure_str(status_attrs_dict['nsds5replicalastupdatestatus'][0]),
- 'init-in-progress': ensure_str(status_attrs_dict['nsds5beginreplicarefresh'][0]),
'last-init-start': ensure_str(status_attrs_dict['nsds5replicalastinitstart'][0]),
'last-init-end': ensure_str(status_attrs_dict['nsds5replicalastinitend'][0]),
'last-init-status': ensure_str(status_attrs_dict['nsds5replicalastinitstatus'][0]),
@@ -343,8 +365,8 @@ class Agreement(DSLdapObject):
return (json.dumps(result))
else:
retstr = (
- "Status for %(cn)s agmt %(nsDS5ReplicaHost)s:"
- "%(nsDS5ReplicaPort)s" "\n"
+ "Status for agreement: \"%(cn)s\" (%(nsDS5ReplicaHost)s:"
+ "%(nsDS5ReplicaPort)s)" "\n"
"Replica Enabled: %(nsds5ReplicaEnabled)s" "\n"
"Update In Progress: %(nsds5replicaUpdateInProgress)s" "\n"
"Last Update Start: %(nsds5replicaLastUpdateStart)s" "\n"
@@ -354,7 +376,6 @@ class Agreement(DSLdapObject):
"Number Of Changes Skipped: %(nsds5replicaChangesSkippedSince"
"Startup)s" "\n"
"Last Update Status: %(nsds5replicaLastUpdateStatus)s" "\n"
- "Init In Progress: %(nsds5BeginReplicaRefresh)s" "\n"
"Last Init Start: %(nsds5ReplicaLastInitStart)s" "\n"
"Last Init End: %(nsds5ReplicaLastInitEnd)s" "\n"
"Last Init Status: %(nsds5ReplicaLastInitStatus)s" "\n"
diff --git a/src/lib389/lib389/chaining.py b/src/lib389/lib389/chaining.py
index 35949d3..a25bbb6 100644
--- a/src/lib389/lib389/chaining.py
+++ b/src/lib389/lib389/chaining.py
@@ -102,17 +102,11 @@ class ChainingLink(DSLdapObject):
self._basedn = "cn=chaining database,cn=plugins,cn=config"
self._mts = MappingTrees(self._instance)
- def get_monitor(self, rdn):
+ def get_monitor(self):
"""Get a MonitorChaining(DSLdapObject) for the chaining link
- :param rdn - The 'cn' value of the chaining link
- :returns - chaining monitor entry"""
- links = ChainingLinks(self._instance).list()
- for link in links:
- cn = ensure_str(link.get_attr_val('cn')).lower()
- if cn == rdn.lower():
- monitor = MonitorChaining(instance=self._instance, dn="cn=monitor,%s" % link._dn)
- return monitor
- return None
+ :returns - chaining monitor entry
+ """
+ return MonitorChaining(instance=self._instance, dn="cn=monitor,%s" % self._dn)
def del_link(self):
"""
diff --git a/src/lib389/lib389/cli_base/__init__.py b/src/lib389/lib389/cli_base/__init__.py
index 14cb999..ab1ce0f 100644
--- a/src/lib389/lib389/cli_base/__init__.py
+++ b/src/lib389/lib389/cli_base/__init__.py
@@ -194,11 +194,14 @@ def _generic_get_entry(inst, basedn, log, manager_class, args=None):
def _generic_get_attr(inst, basedn, log, manager_class, args=None):
mc = manager_class(inst, basedn)
+ vals = {}
for attr in args.attrs:
if args and args.json:
- print(mc.get_attr_vals_json(attr))
+ vals[attr] = mc.get_attr_vals_utf8(attr)
else:
print(mc.display_attr(attr).rstrip())
+ if args.json:
+ print(json.dumps({"type": "entry", "dn": mc._dn, "attrs": vals}))
def _generic_get_dn(inst, basedn, log, manager_class, dn, args=None):
@@ -312,7 +315,6 @@ def _generic_modify(inst, basedn, log, manager_class, selector, args=None):
else:
raise ValueError("Missing modify actions to perform.")
-
class LogCapture(logging.Handler):
"""
This useful class is for intercepting logs, and then making assertions about
@@ -379,4 +381,3 @@ def setup_script_logger(name, verbose=False):
root.addHandler(log_handler)
return log
-
diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py
index 18da186..77ce3dd 100644
--- a/src/lib389/lib389/cli_conf/backend.py
+++ b/src/lib389/lib389/cli_conf/backend.py
@@ -1,5 +1,5 @@
# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2018 Red Hat, Inc.
+# Copyright (C) 2019 Red Hat, Inc.
# Copyright (C) 2019 William Brown <william(a)blackhats.net.au>
# All rights reserved.
#
@@ -303,7 +303,7 @@ def backend_get_subsuffixes(inst, basedn, log, args):
print("No sub-suffixes under this backend")
-def build_node(suffix, be_name, subsuf=False, link=False):
+def build_node(suffix, be_name, subsuf=False, link=False, replicated=False):
"""Build the UI node for a suffix
"""
icon = "glyphicon glyphicon-tree-conifer"
@@ -314,6 +314,9 @@ def build_node(suffix, be_name, subsuf=False, link=False):
if link:
icon = "glyphicon glyphicon-link"
suffix_type = "dblink"
+ if replicated:
+ suffix_type = "replicated"
+
return {
"text": suffix,
"id": suffix,
@@ -348,26 +351,29 @@ def backend_build_tree(inst, be_insts, nodes):
link = False
if is_db_link(inst, sub_be):
link = True
- node['nodes'].append(build_node(mt.get_attr_val_utf8_l('cn'), sub_be, subsuf=True, link=link))
+ node['nodes'].append(build_node(mt.get_attr_val_utf8_l('cn'),
+ sub_be,
+ subsuf=True,
+ link=link))
# Recurse over the new subsuffixes
backend_build_tree(inst, be_insts, node['nodes'])
break
-def print_suffix_tree(nodes, level):
+def print_suffix_tree(nodes, level, log):
"""Print all the nodes and children recursively
"""
if len(nodes) > 0:
for node in nodes:
spaces = " " * level
- print('{}- {}'.format(spaces, node['id']))
+ log.info('{}- {}'.format(spaces, node['id']))
if len(node['nodes']) > 0:
- print_suffix_tree(node['nodes'], level + 2)
+ print_suffix_tree(node['nodes'], level + 2, log)
def backend_get_tree(inst, basedn, log, args):
- """Build a tree model of all the suffixes/sub suffixes nad DB links
+ """Build a tree model of all the suffixes/sub suffixes and DB links
"""
nodes = []
@@ -376,30 +382,28 @@ def backend_get_tree(inst, basedn, log, args):
for be in be_insts:
suffix = be.get_attr_val_utf8_l('nsslapd-suffix')
be_name = be.get_attr_val_utf8('cn')
- try:
- mt = be._mts.get(suffix)
- except ldap.NO_SUCH_OBJECT:
- log.debug("Failed to find the mapping tree entry using this suffix: {}".format(suffix))
- continue
+ mt = be._mts.get(suffix)
sub = mt.get_attr_val_utf8_l('nsslapd-parent-suffix')
if sub is not None:
- # Skip sub suffixes for now, we will get them later
continue
nodes.append(build_node(suffix, be_name))
# No suffixes, return empty list
if len(nodes) == 0:
- return nodes
-
- # Build the tree
- be_insts = Backends(inst).list()
- backend_build_tree(inst, be_insts, nodes)
-
- # Done
- if args.json:
- print(json.dumps(nodes))
+ if args.json:
+ log.info(json.dumps(nodes))
+ else:
+ log.info("There are no suffixes defined")
else:
- print_suffix_tree(nodes, 1)
+ # Build the tree
+ be_insts = Backends(inst).list()
+ backend_build_tree(inst, be_insts, nodes)
+
+ # Done
+ if args.json:
+ log.info(json.dumps(nodes))
+ else:
+ print_suffix_tree(nodes, 1, log)
def backend_set(inst, basedn, log, args):
@@ -1060,4 +1064,4 @@ def create_parser(subparsers):
# Get Suffix Tree (for use in web console)
#######################################################
get_tree_parser = subcommands.add_parser('get-tree', help='Get a representation of the suffix tree')
- get_tree_parser.set_defaults(func=backend_get_tree)
\ No newline at end of file
+ get_tree_parser.set_defaults(func=backend_get_tree)
diff --git a/src/lib389/lib389/cli_conf/monitor.py b/src/lib389/lib389/cli_conf/monitor.py
new file mode 100644
index 0000000..a704bea
--- /dev/null
+++ b/src/lib389/lib389/cli_conf/monitor.py
@@ -0,0 +1,88 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2019 William Brown <william(a)blackhats.net.au>
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+
+from lib389.monitor import (Monitor, MonitorLDBM, MonitorSNMP)
+from lib389.chaining import (ChainingLinks)
+from lib389.backend import Backends
+
+
+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 monitor(inst, basedn, log, args):
+ monitor = Monitor(inst)
+ _format_status(log, monitor, args.json)
+
+
+def backend_monitor(inst, basedn, log, args):
+ bes = Backends(inst)
+ if args.backend:
+ be = bes.get(args.backend)
+ be_monitor = be.get_monitor()
+ _format_status(log, be_monitor, args.json)
+ else:
+ for be in bes.list():
+ be_monitor = be.get_monitor()
+ _format_status(log, be_monitor, args.json)
+ # Inejct a new line for now ... see https://pagure.io/389-ds-base/issue/50189
+ log.info("")
+
+
+def ldbm_monitor(inst, basedn, log, args):
+ ldbm_monitor = MonitorLDBM(inst)
+ _format_status(log, ldbm_monitor, args.json)
+
+
+def snmp_monitor(inst, basedn, log, args):
+ snmp_monitor = MonitorSNMP(inst)
+ _format_status(log, snmp_monitor, args.json)
+
+
+def chaining_monitor(inst, basedn, log, args):
+ links = ChainingLinks(inst)
+ if args.backend:
+ link = links.get(args.backend)
+ link_monitor = link.get_monitor()
+ _format_status(log, link_monitor, args.json)
+ else:
+ 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
+ log.info("")
+
+
+def create_parser(subparsers):
+ monitor_parser = subparsers.add_parser('monitor', help="Monitor the state of the instance")
+ subcommands = monitor_parser.add_subparsers(help='action')
+
+ server_parser = subcommands.add_parser('server', help="Monitor the server statistics, connectinos and operations")
+ server_parser.set_defaults(func=monitor)
+
+ ldbm_parser = subcommands.add_parser('ldbm', help="Monitor the ldbm statistics, such as dbcache")
+ ldbm_parser.set_defaults(func=ldbm_monitor)
+
+ backend_parser = subcommands.add_parser('backend', help="Monitor the behaviour of a backend database")
+ backend_parser.add_argument('backend', nargs='?', help="Optional name of the backend to monitor")
+ backend_parser.set_defaults(func=backend_monitor)
+
+ snmp_parser = subcommands.add_parser('snmp', help="Monitor the SNMP statistics")
+ snmp_parser.set_defaults(func=snmp_monitor)
+
+ 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)
\ No newline at end of file
diff --git a/src/lib389/lib389/cli_conf/replication.py b/src/lib389/lib389/cli_conf/replication.py
index 96e7c02..b25eba6 100644
--- a/src/lib389/lib389/cli_conf/replication.py
+++ b/src/lib389/lib389/cli_conf/replication.py
@@ -16,7 +16,6 @@ from lib389.replica import Replicas, BootstrapReplicationManager
from lib389.tasks import CleanAllRUVTask, AbortCleanAllRUVTask
from lib389._mapped_object import DSLdapObjects
-
arg_to_attr = {
# replica config
'replica_id': 'nsds5replicaid',
@@ -196,7 +195,7 @@ def enable_replication(inst, basedn, log, args):
# Some other bad error
raise ValueError("Failed to create replication manager entry: " + str(e))
- print("Replication successfully enabled for \"{}\"".format(repl_root))
+ log.info("Replication successfully enabled for \"{}\"".format(repl_root))
def disable_replication(inst, basedn, log, args):
@@ -206,7 +205,7 @@ def disable_replication(inst, basedn, log, args):
replica.delete()
except ldap.NO_SUCH_OBJECT:
raise ValueError("Backend \"{}\" is not enabled for replication".format(args.suffix))
- print("Replication disabled for \"{}\"".format(args.suffix))
+ log.info("Replication disabled for \"{}\"".format(args.suffix))
def promote_replica(inst, basedn, log, args):
@@ -224,7 +223,7 @@ def promote_replica(inst, basedn, log, args):
raise ValueError("Invalid role ({}), you must use either \"master\" or \"hub\"".format(role))
replica.promote(newrole, binddn=args.bind_dn, binddn_group=args.bind_group_dn, rid=args.replica_id)
- print("Successfully promoted replica to \"{}\"".format(role))
+ log.info("Successfully promoted replica to \"{}\"".format(role))
def demote_replica(inst, basedn, log, args):
@@ -240,7 +239,7 @@ def demote_replica(inst, basedn, log, args):
raise ValueError("Invalid role ({}), you must use either \"hub\" or \"consumer\"".format(role))
replica.demote(newrole)
- print("Successfully demoted replica to \"{}\"".format(role))
+ log.info("Successfully demoted replica to \"{}\"".format(role))
def list_suffixes(inst, basedn, log, args):
@@ -250,22 +249,44 @@ def list_suffixes(inst, basedn, log, args):
suffixes.append(replica.get_suffix())
if args.json:
- print(json.dumps({"type": "list", "items": suffixes}))
+ log.info(json.dumps({"type": "list", "items": suffixes}))
else:
if len(suffixes) == 0:
- print("There are no replicated suffixes")
+ log.info("There are no replicated suffixes")
else:
for suffix in suffixes:
- print(suffix)
+ log.info(suffix)
+
+
+def get_repl_status(inst, basedn, log, args):
+ replicas = Replicas(inst)
+ replica = replicas.get(args.suffix)
+ status = replica.status(binddn=args.bind_dn, bindpw=args.bind_passwd)
+ if args.json:
+ log.info(json.dumps({"type": "list", "items": status}))
+ else:
+ for agmt in status:
+ log.info(agmt)
+
+
+def get_repl_winsync_status(inst, basedn, log, args):
+ replicas = Replicas(inst)
+ replica = replicas.get(args.suffix)
+ status = replica.status(binddn=args.bind_dn, bindpw=args.bind_passwd, winsync=True)
+ if args.json:
+ log.info(json.dumps({"type": "list", "items": status}))
+ else:
+ for agmt in status:
+ log.info(agmt)
def get_repl_config(inst, basedn, log, args):
replicas = Replicas(inst)
replica = replicas.get(args.suffix)
if args and args.json:
- print(replica.get_all_attrs_json())
+ log.info(replica.get_all_attrs_json())
else:
- print(replica.display())
+ log.info(replica.display())
def set_repl_config(inst, basedn, log, args):
@@ -311,7 +332,7 @@ def set_repl_config(inst, basedn, log, args):
elif not did_something:
raise ValueError("There are no changes to set in the replica")
- print("Successfully updated replication configuration")
+ log.info("Successfully updated replication configuration")
def create_cl(inst, basedn, log, args):
@@ -323,7 +344,7 @@ def create_cl(inst, basedn, log, args):
})
except ldap.ALREADY_EXISTS:
raise ValueError("Changelog already exists")
- print("Successfully created replication changelog")
+ log.info("Successfully created replication changelog")
def delete_cl(inst, basedn, log, args):
@@ -332,7 +353,7 @@ def delete_cl(inst, basedn, log, args):
cl.delete()
except ldap.NO_SUCH_OBJECT:
raise ValueError("There is no changelog to delete")
- print("Successfully deleted replication changelog")
+ log.info("Successfully deleted replication changelog")
def set_cl(inst, basedn, log, args):
@@ -351,15 +372,15 @@ def set_cl(inst, basedn, log, args):
elif not did_something:
raise ValueError("There are no changes to set for the replication changelog")
- print("Successfully updated replication changelog")
+ log.info("Successfully updated replication changelog")
def get_cl(inst, basedn, log, args):
cl = Changelog5(inst)
if args and args.json:
- print(cl.get_all_attrs_json())
+ log.info(cl.get_all_attrs_json())
else:
- print(cl.display())
+ log.info(cl.display())
def create_repl_manager(inst, basedn, log, args):
@@ -392,7 +413,7 @@ def create_repl_manager(inst, basedn, log, args):
if repl_manager_password_confirm == repl_manager_password:
break
else:
- print("Passwords do not match!\n")
+ log.info("Passwords do not match!\n")
repl_manager_password = ""
repl_manager_password_confirm = ""
@@ -410,9 +431,9 @@ def create_repl_manager(inst, basedn, log, args):
replica.add('nsds5ReplicaBindDN', manager_dn)
except ldap.TYPE_OR_VALUE_EXISTS:
pass
- print("Successfully created replication manager: " + manager_dn)
+ log.info("Successfully created replication manager: " + manager_dn)
except ldap.ALREADY_EXISTS:
- print("Replication Manager ({}) already exists, recreating it...".format(manager_dn))
+ log.info("Replication Manager ({}) already exists, recreating it...".format(manager_dn))
# Already there, but could have different password. Delete and recreate
manager.delete()
manager.create(properties={
@@ -428,7 +449,7 @@ def create_repl_manager(inst, basedn, log, args):
except ldap.TYPE_OR_VALUE_EXISTS:
pass
- print("Successfully created replication manager: " + manager_dn)
+ log.info("Successfully created replication manager: " + manager_dn)
def del_repl_manager(inst, basedn, log, args):
@@ -443,7 +464,7 @@ def del_repl_manager(inst, basedn, log, args):
replicas = Replicas(inst)
replica = replicas.get(args.suffix)
replica.remove('nsds5ReplicaBindDN', manager_dn)
- print("Successfully deleted replication manager: " + manager_dn)
+ log.info("Successfully deleted replication manager: " + manager_dn)
#
@@ -462,9 +483,9 @@ def list_agmts(inst, basedn, log, args):
# Append decoded json object, because we are going to dump it later
result['items'].append(json.loads(entry))
else:
- print(agmt.display())
+ log.info(agmt.display())
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def add_agmt(inst, basedn, log, args):
@@ -524,7 +545,7 @@ def add_agmt(inst, basedn, log, args):
except ldap.ALREADY_EXISTS:
raise ValueError("A replication agreement with the same name already exists")
- print("Successfully created replication agreement \"{}\"".format(get_agmt_name(args)))
+ log.info("Successfully created replication agreement \"{}\"".format(get_agmt_name(args)))
if args.init:
init_agmt(inst, basedn, log, args)
@@ -532,25 +553,25 @@ def add_agmt(inst, basedn, log, args):
def delete_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args)
agmt.delete()
- print("Agreement has been successfully deleted")
+ log.info("Agreement has been successfully deleted")
def enable_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args)
agmt.resume()
- print("Agreement has been enabled")
+ log.info("Agreement has been enabled")
def disable_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args)
agmt.pause()
- print("Agreement has been disabled")
+ log.info("Agreement has been disabled")
def init_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args)
agmt.begin_reinit()
- print("Agreement initialization started...")
+ log.info("Agreement initialization started...")
def check_init_agmt(inst, basedn, log, args):
@@ -564,9 +585,9 @@ def check_init_agmt(inst, basedn, log, args):
elif error:
status = "Agreement initialization failed."
if args.json:
- print(json.dumps(status))
+ log.info(json.dumps(status))
else:
- print(status)
+ log.info(status)
def set_agmt(inst, basedn, log, args):
@@ -592,15 +613,15 @@ def set_agmt(inst, basedn, log, args):
elif not did_something:
raise ValueError("There are no changes to set in the agreement")
- print("Successfully updated agreement")
+ log.info("Successfully updated agreement")
def get_repl_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args)
if args.json:
- print(agmt.get_all_attrs_json())
+ log.info(agmt.get_all_attrs_json())
else:
- print(agmt.display())
+ log.info(agmt.display())
def poke_agmt(inst, basedn, log, args):
@@ -608,7 +629,7 @@ def poke_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args)
agmt.pause()
agmt.resume()
- print("Agreement has been poked")
+ log.info("Agreement has been poked")
def get_agmt_status(inst, basedn, log, args):
@@ -618,7 +639,7 @@ def get_agmt_status(inst, basedn, log, args):
while args.bind_passwd == "":
args.bind_passwd = getpass("Enter password for \"{}\": ".format(args.bind_dn))
status = agmt.status(use_json=args.json, binddn=args.bind_dn, bindpw=args.bind_passwd)
- print(agmt, status)
+ log.info(status)
#
@@ -637,9 +658,9 @@ def list_winsync_agmts(inst, basedn, log, args):
# Append decoded json object, because we are going to dump it later
result['items'].append(json.loads(entry))
else:
- print(agmt.display())
+ log.info(agmt.display())
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
def add_winsync_agmt(inst, basedn, log, args):
@@ -698,7 +719,7 @@ def add_winsync_agmt(inst, basedn, log, args):
except ldap.ALREADY_EXISTS:
raise ValueError("A replication agreement with the same name already exists")
- print("Successfully created winsync replication agreement \"{}\"".format(get_agmt_name(args)))
+ log.info("Successfully created winsync replication agreement \"{}\"".format(get_agmt_name(args)))
if args.init:
init_winsync_agmt(inst, basedn, log, args)
@@ -706,7 +727,7 @@ def add_winsync_agmt(inst, basedn, log, args):
def delete_winsync_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args, winsync=True)
agmt.delete()
- print("Agreement has been successfully deleted")
+ log.info("Agreement has been successfully deleted")
def set_winsync_agmt(inst, basedn, log, args):
@@ -727,25 +748,25 @@ def set_winsync_agmt(inst, basedn, log, args):
elif not did_something:
raise ValueError("There are no changes to set in the agreement")
- print("Successfully updated agreement")
+ log.info("Successfully updated agreement")
def enable_winsync_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args, winsync=True)
agmt.resume()
- print("Agreement has been enabled")
+ log.info("Agreement has been enabled")
def disable_winsync_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args, winsync=True)
agmt.pause()
- print("Agreement has been disabled")
+ log.info("Agreement has been disabled")
def init_winsync_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args, winsync=True)
agmt.begin_reinit()
- print("Agreement initialization started...")
+ log.info("Agreement initialization started...")
def check_winsync_init_agmt(inst, basedn, log, args):
@@ -759,17 +780,17 @@ def check_winsync_init_agmt(inst, basedn, log, args):
elif error:
status = "Agreement initialization failed."
if args.json:
- print(json.dumps(status))
+ log.info(json.dumps(status))
else:
- print(status)
+ log.info(status)
def get_winsync_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args, winsync=True)
if args.json:
- print(agmt.get_all_attrs_json())
+ log.info(agmt.get_all_attrs_json())
else:
- print(agmt.display())
+ log.info(agmt.display())
def poke_winsync_agmt(inst, basedn, log, args):
@@ -777,13 +798,13 @@ def poke_winsync_agmt(inst, basedn, log, args):
agmt = get_agmt(inst, args, winsync=True)
agmt.pause()
agmt.resume()
- print("Agreement has been poked")
+ log.info("Agreement has been poked")
def get_winsync_agmt_status(inst, basedn, log, args):
agmt = get_agmt(inst, args, winsync=True)
status = agmt.status(winsync=True, use_json=args.json)
- print(agmt, status)
+ log.info(status)
#
@@ -798,9 +819,9 @@ def run_cleanallruv(inst, basedn, log, args):
clean_task.create(properties=properties)
rdn = clean_task.rdn
if args.json:
- print(json.dumps(rdn))
+ log.info(json.dumps(rdn))
else:
- print('Created task ' + rdn)
+ log.info('Created task ' + rdn)
def list_cleanallruv(inst, basedn, log, args):
@@ -813,17 +834,20 @@ def list_cleanallruv(inst, basedn, log, args):
tasks_found = False
for task in tasks:
tasks_found = True
+ if args.suffix is not None:
+ if args.suffix.lower() != task.get_attr_val_utf8_l('replica-base-dn'):
+ continue
if args.json:
entry = task.get_all_attrs_json()
# Append decoded json object, because we are going to dump it later
result['items'].append(json.loads(entry))
else:
- print(task.display())
+ log.info(task.display())
if args.json:
- print(json.dumps(result))
+ log.info(json.dumps(result))
else:
if not tasks_found:
- print("No CleanAllRUV tasks found")
+ log.info("No CleanAllRUV tasks found")
def abort_cleanallruv(inst, basedn, log, args):
@@ -835,6 +859,32 @@ def abort_cleanallruv(inst, basedn, log, args):
clean_task.create(properties=properties)
+def list_abort_cleanallruv(inst, basedn, log, args):
+ tasksobj = DSLdapObjects(inst)
+ tasksobj._basedn = "cn=abort cleanallruv, cn=tasks, cn=config"
+ tasksobj._scope = ldap.SCOPE_ONELEVEL
+ tasksobj._objectclasses = ['top']
+ tasks = tasksobj.list()
+ result = {"type": "list", "items": []}
+ tasks_found = False
+ for task in tasks:
+ tasks_found = True
+ if args.suffix is not None:
+ if args.suffix.lower() != task.get_attr_val_utf8_l('replica-base-dn'):
+ continue
+ if args.json:
+ entry = task.get_all_attrs_json()
+ # Append decoded json object, because we are going to dump it later
+ result['items'].append(json.loads(entry))
+ else:
+ log.info(task.display())
+ if args.json:
+ log.info(json.dumps(result))
+ else:
+ if not tasks_found:
+ log.info("No CleanAllRUV abort tasks found")
+
+
def create_parser(subparsers):
############################################
@@ -860,6 +910,18 @@ def create_parser(subparsers):
repl_list_parser = repl_subcommands.add_parser('list', help='List all the replicated suffixes')
repl_list_parser.set_defaults(func=list_suffixes)
+ repl_status_parser = repl_subcommands.add_parser('status', help='Get the current status of all the replication agreements')
+ repl_status_parser.set_defaults(func=get_repl_status)
+ repl_status_parser.add_argument('--suffix', required=True, help="The DN of the replication suffix")
+ repl_status_parser.add_argument('--bind-dn', help="The DN to use to authenticate to the consumer")
+ repl_status_parser.add_argument('--bind-passwd', help="The password for the bind DN")
+
+ repl_winsync_status_parser = repl_subcommands.add_parser('winsync-status', help='Get the current status of all the replication agreements')
+ repl_winsync_status_parser.set_defaults(func=get_repl_winsync_status)
+ repl_winsync_status_parser.add_argument('--suffix', required=True, help="The DN of the replication suffix")
+ repl_winsync_status_parser.add_argument('--bind-dn', help="The DN to use to authenticate to the consumer")
+ repl_winsync_status_parser.add_argument('--bind-passwd', help="The password for the bind DN")
+
repl_promote_parser = repl_subcommands.add_parser('promote', help='Promte replica to a Hub or Master')
repl_promote_parser.set_defaults(func=promote_replica)
repl_promote_parser.add_argument('--suffix', required=True, help="The DN of the replication suffix to promote")
@@ -981,7 +1043,7 @@ def create_parser(subparsers):
agmt_status_parser.set_defaults(func=get_agmt_status)
agmt_status_parser.add_argument('AGMT_NAME', nargs=1, help='The name of the replication agreement')
agmt_status_parser.add_argument('--suffix', required=True, help="The DN of the replication suffix")
- agmt_status_parser.add_argument('--bind-dn', help="Set the DN to bind to the consumer")
+ agmt_status_parser.add_argument('--bind-dn', help="The DN to use to authenticate to the consumer")
agmt_status_parser.add_argument('--bind-passwd', help="The password for the bind DN")
# Delete
@@ -1187,8 +1249,9 @@ def create_parser(subparsers):
task_cleanallruv.add_argument('--force-cleaning', action='store_true', default=False,
help="Ignore errors and do a best attempt to clean all the replicas")
- task_cleanallruv_list = task_subcommands.add_parser('list-cleanallruv', help='List all the running CleanAllRUV Tasks')
+ task_cleanallruv_list = task_subcommands.add_parser('list-cleanruv-tasks', help='List all the running CleanAllRUV tasks')
task_cleanallruv_list.set_defaults(func=list_cleanallruv)
+ task_cleanallruv_list.add_argument('--suffix', help="List only tasks from for suffix")
# Abort cleanallruv
task_abort_cleanallruv = task_subcommands.add_parser('abort-cleanallruv', help='Abort cleanallruv tasks')
@@ -1198,4 +1261,7 @@ def create_parser(subparsers):
task_abort_cleanallruv.add_argument('--certify', action='store_true', default=False,
help="Enforce that the abort task completed on all replicas")
+ task_abort_cleanallruv_list = task_subcommands.add_parser('list-abortruv-tasks', help='List all the running CleanAllRUV abort Tasks')
+ task_abort_cleanallruv_list.set_defaults(func=list_abort_cleanallruv)
+ task_abort_cleanallruv_list.add_argument('--suffix', help="List only tasks from for suffix")
diff --git a/src/lib389/lib389/monitor.py b/src/lib389/lib389/monitor.py
index 0102630..9c11d34 100644
--- a/src/lib389/lib389/monitor.py
+++ b/src/lib389/lib389/monitor.py
@@ -1,16 +1,14 @@
# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2015 Red Hat, Inc.
+# Copyright (C) 2019 Red Hat, Inc.
# All rights reserved.
#
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
-import ldap
-from ldap import filter as ldap_filter
from lib389._constants import *
-from lib389._mapped_object import DSLdapObjects, DSLdapObject
-from lib389.utils import (ds_is_older, ensure_str)
+from lib389._mapped_object import DSLdapObject
+from lib389.utils import (ds_is_older)
class Monitor(DSLdapObject):
@@ -105,19 +103,16 @@ class MonitorLDBM(DSLdapObject):
'normalizeddncachehits',
'normalizeddncachemisses',
'normalizeddncachehitratio',
+ 'normalizeddncacheevictions',
'currentnormalizeddncachesize',
'maxnormalizeddncachesize',
- 'currentnormalizeddncachecount'
+ 'currentnormalizeddncachecount',
+ 'normalizeddncachethreadsize',
+ 'normalizeddncachethreadslots'
])
def get_status(self, use_json=False):
- if use_json:
- print(self.get_attrs_vals_json(self._backend_keys))
- else:
- attr_dict = self.get_attrs_vals(self._backend_keys)
- print('dn: ' + self._dn)
- for k, v in list(attr_dict.items()):
- print('{}: {}'.format(k, ensure_str(v[0])))
+ return self.get_attrs_vals_utf8(self._backend_keys)
class MonitorBackend(DSLdapObject):
@@ -156,13 +151,7 @@ class MonitorBackend(DSLdapObject):
])
def get_status(self, use_json=False):
- if use_json:
- print(self.get_attrs_vals_json(self._backend_keys))
- else:
- attr_dict = self.get_attrs_vals(self._backend_keys)
- print('dn: ' + self._dn)
- for k, v in list(attr_dict.items()):
- print('{}: {}'.format(k, ensure_str(v[0])))
+ return self.get_attrs_vals_utf8(self._backend_keys)
class MonitorChaining(DSLdapObject):
@@ -188,10 +177,50 @@ class MonitorChaining(DSLdapObject):
self._protected = False
def get_status(self, use_json=False):
- if use_json:
- print(self.get_attrs_vals_json(self._chaining_keys))
- else:
- attr_dict = self.get_attrs_vals(self._chaining_keys)
- print('dn: ' + self._dn)
- for k, v in list(attr_dict.items()):
- print('{}: {}'.format(k, ensure_str(v[0])))
+ return self.get_attrs_vals_utf8(self._chaining_keys)
+
+
+class MonitorSNMP(DSLdapObject):
+ """
+ """
+ def __init__(self, instance, dn=None):
+ super(MonitorSNMP, self).__init__(instance=instance, dn=dn)
+ self._dn = DN_MONITOR_SNMP
+ self._snmp_keys = [
+ 'anonymousbinds',
+ 'unauthbinds',
+ 'simpleauthbinds',
+ 'strongauthbinds',
+ 'bindsecurityerrors',
+ 'inops',
+ 'readops',
+ 'compareops',
+ 'addentryops',
+ 'removeentryops',
+ 'modifyentryops',
+ 'modifyrdnops',
+ 'listops',
+ 'searchops',
+ 'onelevelsearchops',
+ 'wholesubtreesearchops',
+ 'referrals',
+ 'chainings',
+ 'securityerrors',
+ 'errors',
+ 'connections',
+ 'connectionseq',
+ 'connectionsinmaxthreads',
+ 'connectionsmaxthreadscount',
+ 'bytesrecv',
+ 'bytessent',
+ 'entriesreturned',
+ 'referralsreturned',
+ 'masterentries',
+ 'copyentries',
+ 'cacheentries',
+ 'cachehits',
+ 'slavehits'
+ ]
+
+ def get_status(self, use_json=False):
+ return self.get_attrs_vals_utf8(self._snmp_keys)
diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py
index a462c98..333645b 100644
--- a/src/lib389/lib389/replica.py
+++ b/src/lib389/lib389/replica.py
@@ -11,7 +11,8 @@ import decimal
import time
import logging
import uuid
-
+import json
+from operator import itemgetter
from itertools import permutations
from lib389._constants import *
from lib389.properties import *
@@ -22,6 +23,7 @@ from lib389.passwd import password_generate
from lib389.mappingTree import MappingTrees
from lib389.agreement import Agreements
from lib389.changelog import Changelog5
+from lib389.tombstone import Tombstones
from lib389.idm.domain import Domain
from lib389.idm.group import Groups
@@ -1250,6 +1252,25 @@ class Replica(DSLdapObject):
return self._suffix
+ def status(self, binddn=None, bindpw=None, winsync=False):
+ """Get a list of the status for every agreement
+ """
+ agmtList = []
+ agmts = Agreements(self._instance, self.dn, winsync=winsync).list()
+ for agmt in agmts:
+ raw_status = agmt.status(binddn=binddn, bindpw=bindpw, use_json=True, winsync=winsync)
+ agmtList.append(json.loads(raw_status))
+
+ # sort the list of agreements by the lag time
+ sortedList = sorted(agmtList, key=itemgetter('replication-lag-time'))
+ return(sortedList)
+
+ def get_tombstone_count(self):
+ """Get the number of tombstones
+ """
+ tombstones = Tombstones(self._instance, self._suffix).list()
+ return len(tombstones)
+
class Replicas(DSLdapObjects):
"""Replica DSLdapObjects for all replicas
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50305 - Revise CleanAllRUV task restart process
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 1ebaff4 Ticket 50305 - Revise CleanAllRUV task restart process
1ebaff4 is described below
commit 1ebaff46aef3f3c521239a559b16aef055e67a90
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Thu Mar 28 17:46:54 2019 -0400
Ticket 50305 - Revise CleanAllRUV task restart process
Bug Description: If the server was stopped while a CleanAllRUV task was
running the task gets marked in the replica config entry
so it knowns to resume the task at server startup. The
problem is that when it resumed it just fires off the
task thread, and did not create a new Slapi_Task entry.
This makes it impossible to track these tasks that got
resumed.
Fix Description: There were a few things wrong with the resume process,
including it was harded coded to only handle a maximum
of 4 tasks. We also were not recording all the required
information needed to resume the task.
Now "resume" process can handle an infinite number of
tasks, and it creates fresh Slapi_Task entries so the
tasks can be tracked.
CI tested & ASAN approved
https://pagure.io/389-ds-base/issue/50305
Reviewed by: lkrispenz(Thanks!)
(cherry picked from commit d08f7eb688102cd54bbacd009d162f0cc16cd5fe)
---
.../tests/suites/replication/cleanallruv_test.py | 11 +-
ldap/servers/plugins/replication/repl5.h | 8 +-
.../servers/plugins/replication/repl5_mtnode_ext.c | 2 +
ldap/servers/plugins/replication/repl5_replica.c | 373 ++++++++++++---------
.../plugins/replication/repl5_replica_config.c | 128 +++----
ldap/servers/plugins/replication/repl_extop.c | 2 +-
ldap/servers/slapd/task.c | 20 +-
7 files changed, 299 insertions(+), 245 deletions(-)
diff --git a/dirsrvtests/tests/suites/replication/cleanallruv_test.py b/dirsrvtests/tests/suites/replication/cleanallruv_test.py
index 74eae91..2b244da 100644
--- a/dirsrvtests/tests/suites/replication/cleanallruv_test.py
+++ b/dirsrvtests/tests/suites/replication/cleanallruv_test.py
@@ -104,7 +104,11 @@ def task_done(topology_m4, task_dn, timeout=60):
while not done and count < timeout:
try:
entry = topology_m4.ms["master1"].getEntry(task_dn, attrlist=attrlist)
- if not entry or entry.nsTaskExitCode:
+ if entry is not None:
+ if entry.hasAttr('nsTaskExitCode'):
+ done = True
+ break
+ else:
done = True
break
except ldap.NO_SUCH_OBJECT:
@@ -142,7 +146,7 @@ def restore_master4(topology_m4):
@pytest.fixture()
def m4rid(request, topology_m4):
- log.debug("Wait a bit before the reset - it is required fot the slow machines")
+ log.debug("Wait a bit before the reset - it is required for the slow machines")
time.sleep(5)
log.debug("-------------- BEGIN RESET of m4 -----------------")
repl = ReplicationManager(DEFAULT_SUFFIX)
@@ -468,6 +472,9 @@ def test_abort_restart(topology_m4, m4rid):
# Start master 3
topology_m4.ms["master3"].start()
+ # Need to wait 5 seconds before server processes any leftover tasks
+ time.sleep(6)
+
# Check master 1 tried to run abort task. We expect the abort task to be aborted.
if not topology_m4.ms["master1"].searchErrorsLog('Aborting abort task'):
log.fatal('test_abort_restart: Abort task did not restart')
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
index d271b87..138578d 100644
--- a/ldap/servers/plugins/replication/repl5.h
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -728,7 +728,7 @@ void replica_update_ruv_consumer(Replica *r, RUV *supplier_ruv);
Slapi_Entry *get_in_memory_ruv(Slapi_DN *suffix_sdn);
int replica_write_ruv(Replica *r);
char *replica_get_dn(Replica *r);
-void replica_check_for_tasks(Replica *r, Slapi_Entry *e);
+void replica_check_for_tasks(time_t when, void *arg);
void replica_update_state(time_t when, void *arg);
void replica_reset_csn_pl(Replica *r);
uint64_t replica_get_protocol_timeout(Replica *r);
@@ -813,7 +813,7 @@ int replica_config_init(void);
void replica_config_destroy(void);
int get_replica_type(Replica *r);
int replica_execute_cleanruv_task_ext(Object *r, ReplicaId rid);
-void add_cleaned_rid(cleanruv_data *data, char *maxcsn);
+void add_cleaned_rid(cleanruv_data *data);
int is_cleaned_rid(ReplicaId rid);
int replica_cleanall_ruv_abort(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
void replica_cleanallruv_thread_ext(void *arg);
@@ -825,9 +825,9 @@ int process_repl_agmts(Replica *replica, int *agmt_info, char *oid, Slapi_Task *
int decode_cleanruv_payload(struct berval *extop_value, char **payload);
struct berval *create_cleanruv_payload(char *value);
void ruv_get_cleaned_rids(RUV *ruv, ReplicaId *rids);
-void add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root);
+void add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root, char *certify_all, PRBool original_task);
int is_task_aborted(ReplicaId rid);
-void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root, int skip);
+void delete_aborted_rid(Replica *replica, ReplicaId rid, char *repl_root, char *certify_all, PRBool original_task, int skip);
int is_pre_cleaned_rid(ReplicaId rid);
void set_cleaned_rid(ReplicaId rid);
void cleanruv_log(Slapi_Task *task, int rid, char *task_type, int sev_level, char *fmt, ...);
diff --git a/ldap/servers/plugins/replication/repl5_mtnode_ext.c b/ldap/servers/plugins/replication/repl5_mtnode_ext.c
index 466943d..745bd51 100644
--- a/ldap/servers/plugins/replication/repl5_mtnode_ext.c
+++ b/ldap/servers/plugins/replication/repl5_mtnode_ext.c
@@ -101,6 +101,8 @@ multimaster_mtnode_construct_replicas()
ext->replica = NULL;
}
}
+ /* Wait a few seconds for everything to startup before resuming any replication tasks */
+ slapi_eq_once(replica_check_for_tasks, (void *)replica_get_root(r), time(NULL) + 5);
}
}
}
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
index 79c79c2..b3d6198 100644
--- a/ldap/servers/plugins/replication/repl5_replica.c
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -236,8 +236,6 @@ replica_new_from_entry(Slapi_Entry *e, char *errortext, PRBool is_add_operation)
1000 * r->tombstone_reap_interval);
}
- replica_check_for_tasks(r, e);
-
done:
if (rc != 0 && r) {
replica_destroy((void **)&r);
@@ -2101,12 +2099,55 @@ _replica_init_from_config(Replica *r, Slapi_Entry *e, char *errortext)
return (_replica_check_validity(r));
}
+static void
+replica_delete_task_config(Slapi_Entry *e, char *attr, char *value)
+{
+ Slapi_PBlock *modpb;
+ struct berval *vals[2];
+ struct berval val[1];
+ LDAPMod *mods[2];
+ LDAPMod mod;
+ int32_t rc = 0;
+
+ val[0].bv_len = strlen(value);
+ val[0].bv_val = value;
+ vals[0] = &val[0];
+ vals[1] = NULL;
+
+ mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
+ mod.mod_type = attr;
+ mod.mod_bvalues = vals;
+ mods[0] = &mod;
+ mods[1] = NULL;
+
+ modpb = slapi_pblock_new();
+ slapi_modify_internal_set_pb(modpb, slapi_entry_get_dn(e), mods, NULL, NULL,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modify_internal_pb(modpb);
+ slapi_pblock_get(modpb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ slapi_pblock_destroy(modpb);
+
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
+ "delete_cleaned_rid_config - Failed to remove task data from (%s) error (%d)\n",
+ slapi_entry_get_dn(e), rc);
+ }
+}
+
void
-replica_check_for_tasks(Replica *r, Slapi_Entry *e)
+replica_check_for_tasks(time_t when __attribute__((unused)), void *arg)
{
+ const Slapi_DN *repl_root = (Slapi_DN *)arg;
+ Slapi_Entry *e = NULL;
+ Replica *r = NULL;
+ Object *repl_obj = NULL;;
char **clean_vals;
- if (e == NULL || ldif_dump_is_running() == PR_TRUE) {
+ e = _replica_get_config_entry(repl_root, NULL);
+ repl_obj = replica_get_replica_from_dn(repl_root);
+ r = (Replica *)object_get_data(repl_obj);
+
+ if (e == NULL || r == NULL || ldif_dump_is_running() == PR_TRUE) {
/* If db2ldif is being run, do not check if there are incomplete tasks */
return;
}
@@ -2115,218 +2156,218 @@ replica_check_for_tasks(Replica *r, Slapi_Entry *e)
* if so set the cleaned rid, and fire off the thread
*/
if ((clean_vals = slapi_entry_attr_get_charray(e, type_replicaCleanRUV)) != NULL) {
- PRThread *thread = NULL;
- struct berval *payload = NULL;
- CSN *maxcsn = NULL;
- ReplicaId rid;
- char csnstr[CSN_STRSIZE];
- char *token = NULL;
- char *forcing;
- PRBool original_task;
- char *csnpart;
- char *ridstr;
- char *iter = NULL;
- int i;
-
- for (i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++) {
- cleanruv_data *data = NULL;
+ for (size_t i = 0; i < CLEANRIDSIZ && clean_vals[i]; i++) {
+ struct timespec ts = slapi_current_rel_time_hr();
+ PRBool original_task = PR_TRUE;
+ Slapi_Entry *task_entry = NULL;
+ Slapi_PBlock *add_pb = NULL;
+ int32_t result = 0;
+ ReplicaId rid;
+ char *token = NULL;
+ char *forcing;
+ char *iter = NULL;
+ char *repl_root = NULL;
+ char *ridstr = NULL;
+ char *rdn = NULL;
+ char *dn = NULL;
+ char *orig_val = slapi_ch_strdup(clean_vals[i]);
/*
- * Set the cleanruv data, and add the cleaned rid
+ * Get all the needed from
*/
token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
if (token) {
rid = atoi(token);
if (rid <= 0 || rid >= READ_ONLY_REPLICA_ID) {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - Invalid replica id(%d) "
- "aborting task.\n",
- rid);
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - "
+ "Invalid replica id(%d) aborting task. Aborting cleaning task!\n", rid);
+ replica_delete_task_config(e, (char *)type_replicaCleanRUV, orig_val);
goto done;
}
} else {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - Unable to parse cleanallruv "
- "data (%s), aborting task.\n",
- clean_vals[i]);
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - "
+ "Unable to parse cleanallruv data (%s), missing rid, aborting task. Aborting cleaning task!\n",
+ clean_vals[i]);
+ replica_delete_task_config(e, (char *)type_replicaCleanRUV, orig_val);
goto done;
}
- csnpart = ldap_utf8strtok_r(iter, ":", &iter);
- maxcsn = csn_new();
- csn_init_by_string(maxcsn, csnpart);
- csn_as_string(maxcsn, PR_FALSE, csnstr);
+
+ /* Get forcing */
forcing = ldap_utf8strtok_r(iter, ":", &iter);
- original_task = PR_TRUE;
- if (forcing == NULL) {
- forcing = "no";
- } else if (!strcasecmp(forcing, "yes") || !strcasecmp(forcing, "no")) {
- /* forcing was correctly set, lets try to read the original task flag */
- token = ldap_utf8strtok_r(iter, ":", &iter);
- if (token && !atoi(token)) {
- original_task = PR_FALSE;
- }
+ if (forcing == NULL || strlen(forcing) > 3) {
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - "
+ "Unable to parse cleanallruv data (%s), missing/invalid force option (%s). Aborting cleaning task!\n",
+ clean_vals[i], forcing ? forcing : "missing force option");
+ replica_delete_task_config(e, (char *)type_replicaCleanRUV, orig_val);
+ goto done;
}
- slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "CleanAllRUV Task - cleanAllRUV task found, "
- "resuming the cleaning of rid(%d)...\n",
- rid);
- /*
- * Create payload
- */
- ridstr = slapi_ch_smprintf("%d:%s:%s:%s", rid, slapi_sdn_get_dn(replica_get_root(r)), csnstr, forcing);
- payload = create_cleanruv_payload(ridstr);
- slapi_ch_free_string(&ridstr);
+ /* Get original task flag */
+ token = ldap_utf8strtok_r(iter, ":", &iter);
+ if (token) {
+ if (!atoi(token)) {
+ original_task = PR_FALSE;
+ }
+ } else {
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - "
+ "Unable to parse cleanallruv data (%s), missing original task flag. Aborting cleaning task!\n",
+ clean_vals[i]);
+ replica_delete_task_config(e, (char *)type_replicaCleanRUV, orig_val);
+ goto done;
+ }
- if (payload == NULL) {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - Startup: Failed to "
- "create extended op payload, aborting task");
- csn_free(&maxcsn);
+ /* Get repl root */
+ token = ldap_utf8strtok_r(iter, ":", &iter);
+ if (token) {
+ repl_root = token;
+ } else {
+ /* no repl root, have to void task */
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - "
+ "Unable to parse cleanallruv data (%s), missing replication root aborting task. Aborting cleaning task!\n",
+ clean_vals[i]);
+ replica_delete_task_config(e, (char *)type_replicaCleanRUV, orig_val);
goto done;
}
+
/*
- * Setup the data struct, and fire off the thread.
+ * We have all our data, now add the task....
*/
- data = (cleanruv_data *)slapi_ch_calloc(1, sizeof(cleanruv_data));
- if (data == NULL) {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - Failed to allocate cleanruv_data.\n");
- csn_free(&maxcsn);
- } else {
- /* setup our data */
- data->repl_obj = NULL;
- data->replica = NULL;
- data->rid = rid;
- data->task = NULL;
- data->maxcsn = maxcsn;
- data->payload = payload;
- data->sdn = slapi_sdn_dup(r->repl_root);
- data->force = slapi_ch_strdup(forcing);
- data->repl_root = NULL;
-
- /* This is a corner case, a cleanAllRuv task was interrupted by a shutdown or a crash
- * We retrieved from type_replicaCleanRUV if the cleanAllRuv request
- * was received from a direct task ADD or if was received via
- * the cleanAllRuv extop.
- */
- data->original_task = original_task;
-
- thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread_ext,
- (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
- PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
- if (thread == NULL) {
- /* log an error and free everything */
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "CleanAllRUV Task - Unable to create cleanAllRUV "
- "thread for rid(%d)\n",
- (int)data->rid);
- csn_free(&maxcsn);
- slapi_sdn_free(&data->sdn);
- ber_bvfree(data->payload);
- slapi_ch_free_string(&data->force);
- slapi_ch_free((void **)&data);
- }
+ slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "CleanAllRUV Task - "
+ "CleanAllRUV task found, resuming the cleaning of rid(%d)...\n", rid);
+
+ add_pb = slapi_pblock_new();
+ task_entry = slapi_entry_alloc();
+ rdn = slapi_ch_smprintf("restarted-%ld", ts.tv_sec);
+ dn = slapi_create_dn_string("cn=%s,cn=cleanallruv, cn=tasks, cn=config", rdn, ts.tv_sec);
+ slapi_entry_init(task_entry, dn, NULL);
+
+ ridstr = slapi_ch_smprintf("%d", rid);
+ slapi_entry_add_string(task_entry, "objectclass", "top");
+ slapi_entry_add_string(task_entry, "objectclass", "extensibleObject");
+ slapi_entry_add_string(task_entry, "cn", rdn);
+ slapi_entry_add_string(task_entry, "replica-base-dn", repl_root);
+ slapi_entry_add_string(task_entry, "replica-id", ridstr);
+ slapi_entry_add_string(task_entry, "replica-force-cleaning", forcing);
+ slapi_entry_add_string(task_entry, "replica-original-task", original_task ? "1" : "0");
+
+ slapi_add_entry_internal_set_pb(add_pb, task_entry, NULL,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_add_internal_pb(add_pb);
+ slapi_pblock_get(add_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+ slapi_pblock_destroy(add_pb);
+ if (result != LDAP_SUCCESS) {
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
+ "replica_check_for_tasks - failed to add cleanallruv task entry: %s\n",
+ ldap_err2string(result));
}
- }
- done:
+ done:
+ slapi_ch_free_string(&orig_val);
+ slapi_ch_free_string(&ridstr);
+ slapi_ch_free_string(&rdn);
+ }
slapi_ch_array_free(clean_vals);
}
if ((clean_vals = slapi_entry_attr_get_charray(e, type_replicaAbortCleanRUV)) != NULL) {
- PRThread *thread = NULL;
- struct berval *payload;
- ReplicaId rid;
- char *certify = NULL;
- char *ridstr = NULL;
- char *token = NULL;
- char *repl_root;
- char *iter = NULL;
- int i;
-
- for (i = 0; clean_vals[i]; i++) {
- cleanruv_data *data = NULL;
+ for (size_t i = 0; clean_vals[i]; i++) {
+ struct timespec ts = slapi_current_rel_time_hr();
+ PRBool original_task = PR_TRUE;
+ Slapi_Entry *task_entry = NULL;
+ Slapi_PBlock *add_pb = NULL;
+ ReplicaId rid;
+ char *certify = NULL;
+ char *ridstr = NULL;
+ char *token = NULL;
+ char *repl_root;
+ char *iter = NULL;
+ char *rdn = NULL;
+ char *dn = NULL;
+ char *orig_val = slapi_ch_strdup(clean_vals[i]);
+ int32_t result = 0;
token = ldap_utf8strtok_r(clean_vals[i], ":", &iter);
if (token) {
rid = atoi(token);
if (rid <= 0 || rid >= READ_ONLY_REPLICA_ID) {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Abort CleanAllRUV Task - Invalid replica id(%d) "
- "aborting abort task.\n",
- rid);
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Abort CleanAllRUV Task - "
+ "Invalid replica id(%d) aborting abort task.\n", rid);
+ replica_delete_task_config(e, (char *)type_replicaAbortCleanRUV, orig_val);
goto done2;
}
} else {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Abort CleanAllRUV Task - Unable to parse cleanallruv "
- "data (%s), aborting abort task.\n",
- clean_vals[i]);
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Abort CleanAllRUV Task - "
+ "Unable to parse cleanallruv data (%s), aborting abort task.\n", clean_vals[i]);
+ replica_delete_task_config(e, (char *)type_replicaAbortCleanRUV, orig_val);
goto done2;
}
repl_root = ldap_utf8strtok_r(iter, ":", &iter);
certify = ldap_utf8strtok_r(iter, ":", &iter);
+ /* Get original task flag */
+ token = ldap_utf8strtok_r(iter, ":", &iter);
+ if (token) {
+ if (!atoi(token)) {
+ original_task = PR_FALSE;
+ }
+ } else {
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
+ "Abort CleanAllRUV Task - Unable to parse cleanallruv data (%s), "
+ "missing original task flag. Aborting abort task!\n",
+ clean_vals[i]);
+ replica_delete_task_config(e, (char *)type_replicaAbortCleanRUV, orig_val);
+ goto done;
+ }
+
if (!is_cleaned_rid(rid)) {
- slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "Abort CleanAllRUV Task - Replica id(%d) is not "
- "being cleaned, nothing to abort. Aborting abort task.\n",
- rid);
- delete_aborted_rid(r, rid, repl_root, 0);
+ slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "Abort CleanAllRUV Task - "
+ "Replica id(%d) is not being cleaned, nothing to abort. Aborting abort task.\n", rid);
+ replica_delete_task_config(e, (char *)type_replicaAbortCleanRUV, orig_val);
goto done2;
}
- add_aborted_rid(rid, r, repl_root);
+ add_aborted_rid(rid, r, repl_root, certify, original_task);
stop_ruv_cleaning();
- slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "Abort CleanAllRUV Task - Abort task found, "
- "resuming abort of rid(%d).\n",
- rid);
- /*
- * Setup the data struct, and fire off the abort thread.
- */
- data = (cleanruv_data *)slapi_ch_calloc(1, sizeof(cleanruv_data));
- if (data == NULL) {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Abort CleanAllRUV Task - Failed to allocate cleanruv_data.\n");
- } else {
- ridstr = slapi_ch_smprintf("%d:%s:%s", rid, repl_root, certify);
- payload = create_cleanruv_payload(ridstr);
- slapi_ch_free_string(&ridstr);
-
- if (payload == NULL) {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Abort CleanAllRUV Task - Failed to create extended "
- "op payload\n");
- slapi_ch_free((void **)&data);
- } else {
- /* setup the data */
- data->repl_obj = NULL;
- data->replica = NULL;
- data->rid = rid;
- data->task = NULL;
- data->payload = payload;
- data->repl_root = slapi_ch_strdup(repl_root);
- data->sdn = slapi_sdn_dup(r->repl_root);
- data->certify = slapi_ch_strdup(certify);
-
- /* This is a corner case, a cleanAllRuv task was interrupted by a shutdown or a crash
- * Let's assum this replica was the original receiver of the task.
- * This flag has no impact on Abort cleanAllRuv
- */
- data->original_task = PR_TRUE;
-
- thread = PR_CreateThread(PR_USER_THREAD, replica_abort_task_thread,
- (void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
- PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
- if (thread == NULL) {
- slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name, "Abort CleanAllRUV Task - Unable to create abort cleanAllRUV "
- "thread for rid(%d)\n",
- (int)data->rid);
- slapi_sdn_free(&data->sdn);
- ber_bvfree(data->payload);
- slapi_ch_free_string(&data->repl_root);
- slapi_ch_free_string(&data->certify);
- slapi_ch_free((void **)&data);
- }
- }
+ slapi_log_err(SLAPI_LOG_NOTICE, repl_plugin_name, "Abort CleanAllRUV Task - "
+ "Abort task found, resuming abort of rid(%d).\n", rid);
+
+ add_pb = slapi_pblock_new();
+ task_entry = slapi_entry_alloc();
+ rdn = slapi_ch_smprintf("restarted-abort-%ld", ts.tv_sec);
+ dn = slapi_create_dn_string("cn=%s,cn=abort cleanallruv, cn=tasks, cn=config", rdn, ts.tv_sec);
+ slapi_entry_init(task_entry, dn, NULL);
+
+ ridstr = slapi_ch_smprintf("%d", rid);
+ slapi_entry_add_string(task_entry, "objectclass", "top");
+ slapi_entry_add_string(task_entry, "objectclass", "extensibleObject");
+ slapi_entry_add_string(task_entry, "cn", rdn);
+ slapi_entry_add_string(task_entry, "replica-base-dn", repl_root);
+ slapi_entry_add_string(task_entry, "replica-id", ridstr);
+ slapi_entry_add_string(task_entry, "replica-certify-all", certify);
+ slapi_entry_add_string(task_entry, "replica-original-task", original_task ? "1" : "0");
+
+ slapi_add_entry_internal_set_pb(add_pb, task_entry, NULL,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_add_internal_pb(add_pb);
+ slapi_pblock_get(add_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+ slapi_pblock_destroy(add_pb);
+ if (result != LDAP_SUCCESS) {
+ slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
+ "replica_check_for_tasks - failed to add cleanallruv abort task entry: %s\n",
+ ldap_err2string(result));
}
- }
+ done2:
+ slapi_ch_free_string(&orig_val);
+ slapi_ch_free_string(&ridstr);
+ slapi_ch_free_string(&rdn);
- done2:
+ }
slapi_ch_array_free(clean_vals);
}
+ object_release(repl_obj);
+ slapi_entry_free(e);
}
/* This function updates the entry to contain information generated
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 7ac7e04..eb92a9d 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -57,7 +57,7 @@ static int replica_execute_task(Object *r, const char *task_name, char *returnte
static int replica_execute_cl2ldif_task(Object *r, char *returntext);
static int replica_execute_ldif2cl_task(Object *r, char *returntext);
static int replica_execute_cleanruv_task(Object *r, ReplicaId rid, char *returntext);
-static int replica_execute_cleanall_ruv_task(Object *r, ReplicaId rid, Slapi_Task *task, const char *force_cleaning, char *returntext);
+static int replica_execute_cleanall_ruv_task(Object *r, ReplicaId rid, Slapi_Task *task, const char *force_cleaning, PRBool original_task, char *returntext);
static void replica_cleanallruv_thread(void *arg);
static void replica_send_cleanruv_task(Repl_Agmt *agmt, cleanruv_data *clean_data);
static int check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task);
@@ -216,7 +216,7 @@ replica_config_add(Slapi_PBlock *pb __attribute__((unused)),
/* check rdn is "cn=replica" */
replicardn = slapi_rdn_new_sdn(slapi_entry_get_sdn(e));
if (replicardn) {
- char *nrdn = slapi_rdn_get_nrdn(replicardn);
+ const char *nrdn = slapi_rdn_get_nrdn(replicardn);
if (nrdn == NULL) {
if (errortext != NULL) {
strcpy(errortext, MSG_NOREPLICANORMRDN);
@@ -1078,7 +1078,7 @@ replica_execute_task(Object *r, const char *task_name, char *returntext, int app
}
if (apply_mods) {
Slapi_Task *empty_task = NULL;
- return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, returntext, "no");
+ return replica_execute_cleanall_ruv_task(r, (ReplicaId)temprid, empty_task, "no", PR_TRUE, returntext);
} else
return LDAP_SUCCESS;
} else {
@@ -1409,6 +1409,8 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb __attribute__((unused)),
const char *force_cleaning;
const char *base_dn;
const char *rid_str;
+ const char *orig_val = NULL;
+ PRBool original_task = PR_TRUE;
int rc = SLAPI_DSE_CALLBACK_OK;
/* allocate new task now */
@@ -1454,6 +1456,11 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb __attribute__((unused)),
} else {
force_cleaning = "no";
}
+ if ((orig_val = slapi_fetch_attr(e, "replica-original-task", 0)) != NULL) {
+ if (!strcasecmp(orig_val, "0")) {
+ original_task = PR_FALSE;
+ }
+ }
/*
* Check the rid
*/
@@ -1486,7 +1493,7 @@ replica_cleanall_ruv_task(Slapi_PBlock *pb __attribute__((unused)),
}
/* clean the RUV's */
- rc = replica_execute_cleanall_ruv_task(r, rid, task, force_cleaning, returntext);
+ rc = replica_execute_cleanall_ruv_task(r, rid, task, force_cleaning, original_task, returntext);
out:
if (rc) {
@@ -1509,7 +1516,7 @@ out:
*
*/
static int
-replica_execute_cleanall_ruv_task(Object *r, ReplicaId rid, Slapi_Task *task, const char *force_cleaning, char *returntext __attribute__((unused)))
+replica_execute_cleanall_ruv_task(Object *r, ReplicaId rid, Slapi_Task *task, const char *force_cleaning, PRBool original_task, char *returntext __attribute__((unused)))
{
struct berval *payload = NULL;
Slapi_Task *pre_task = NULL; /* this is supposed to be null for logging */
@@ -1603,7 +1610,7 @@ replica_execute_cleanall_ruv_task(Object *r, ReplicaId rid, Slapi_Task *task, co
/* It is either a consequence of a direct ADD cleanAllRuv task
* or modify of the replica to add nsds5task: cleanAllRuv
*/
- data->original_task = PR_TRUE;
+ data->original_task = original_task;
thread = PR_CreateThread(PR_USER_THREAD, replica_cleanallruv_thread,
(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
@@ -1734,7 +1741,7 @@ replica_cleanallruv_thread(void *arg)
/*
* Add the cleanallruv task to the repl config - so we can handle restarts
*/
- add_cleaned_rid(data, csnstr); /* marks config that we started cleaning a rid */
+ add_cleaned_rid(data); /* marks config that we started cleaning a rid */
cleanruv_log(data->task, data->rid, CLEANALLRUV_ID, SLAPI_LOG_INFO, "Cleaning rid (%d)...", data->rid);
/*
* First, wait for the maxcsn to be covered
@@ -2067,7 +2074,7 @@ check_replicas_are_done_cleaning(cleanruv_data *data)
"Waiting for all the replicas to finish cleaning...");
csn_as_string(data->maxcsn, PR_FALSE, csnstr);
- filter = PR_smprintf("(%s=%d:%s:%s:%d)", type_replicaCleanRUV, (int)data->rid, csnstr, data->force, data->original_task ? 1 : 0);
+ filter = PR_smprintf("(%s=%d:%s:%s:%d:%s)", type_replicaCleanRUV, (int)data->rid, csnstr, data->force, data->original_task ? 1 : 0, data->repl_root);
while (not_all_cleaned && !is_task_aborted(data->rid) && !slapi_is_shutting_down()) {
agmt_obj = agmtlist_get_first_agreement_for_replica(data->replica);
if (agmt_obj == NULL) {
@@ -2540,15 +2547,15 @@ set_cleaned_rid(ReplicaId rid)
* Add the rid and maxcsn to the repl config (so we can resume after a server restart)
*/
void
-add_cleaned_rid(cleanruv_data *cleanruv_data, char *maxcsn)
+add_cleaned_rid(cleanruv_data *cleanruv_data)
{
Slapi_PBlock *pb;
struct berval *vals[2];
struct berval val;
LDAPMod *mods[2];
LDAPMod mod;
- char data[CSN_STRSIZE + 10];
- char *dn;
+ char *data = NULL;
+ char *dn = NULL;
int rc;
ReplicaId rid;
Replica *r;
@@ -2558,13 +2565,15 @@ add_cleaned_rid(cleanruv_data *cleanruv_data, char *maxcsn)
r = cleanruv_data->replica;
forcing = cleanruv_data->force;
- if (r == NULL || maxcsn == NULL) {
+ if (r == NULL) {
return;
}
/*
* Write the rid & maxcsn to the config entry
*/
- val.bv_len = PR_snprintf(data, sizeof(data), "%d:%s:%s:%d", rid, maxcsn, forcing, cleanruv_data->original_task ? 1 : 0);
+ data = slapi_ch_smprintf("%d:%s:%d:%s",
+ rid, forcing, cleanruv_data->original_task ? 1 : 0,
+ cleanruv_data->repl_root);
dn = replica_get_dn(r);
pb = slapi_pblock_new();
mod.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
@@ -2572,6 +2581,7 @@ add_cleaned_rid(cleanruv_data *cleanruv_data, char *maxcsn)
mod.mod_bvalues = vals;
vals[0] = &val;
vals[1] = NULL;
+ val.bv_len = strlen(data);
val.bv_val = data;
mods[0] = &mod;
mods[1] = NULL;
@@ -2585,6 +2595,7 @@ add_cleaned_rid(cleanruv_data *cleanruv_data, char *maxcsn)
"Failed to update replica config (%d), rid (%d)\n",
rc, rid);
}
+ slapi_ch_free_string(&data);
slapi_ch_free_string(&dn);
slapi_pblock_destroy(pb);
}
@@ -2593,7 +2604,7 @@ add_cleaned_rid(cleanruv_data *cleanruv_data, char *maxcsn)
* Add aborted rid and repl root to config in case of a server restart
*/
void
-add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
+add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root, char *certify_all, PRBool original_task)
{
Slapi_PBlock *pb;
struct berval *vals[2];
@@ -2619,7 +2630,7 @@ add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
*/
dn = replica_get_dn(r);
pb = slapi_pblock_new();
- data = PR_smprintf("%d:%s", rid, repl_root);
+ data = PR_smprintf("%d:%s:%s:%d", rid, repl_root, certify_all, original_task ? 1 : 0);
mod.mod_op = LDAP_MOD_ADD | LDAP_MOD_BVALUES;
mod.mod_type = (char *)type_replicaAbortCleanRUV;
mod.mod_bvalues = vals;
@@ -2646,7 +2657,7 @@ add_aborted_rid(ReplicaId rid, Replica *r, char *repl_root)
}
void
-delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root, int skip)
+delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root, char *certify_all, PRBool original_task, int skip)
{
Slapi_PBlock *pb;
LDAPMod *mods[2];
@@ -2674,7 +2685,7 @@ delete_aborted_rid(Replica *r, ReplicaId rid, char *repl_root, int skip)
} else {
/* only remove the config, leave the in-memory rid */
dn = replica_get_dn(r);
- data = PR_smprintf("%d:%s", (int)rid, repl_root);
+ data = PR_smprintf("%d:%s:%s:%d", (int)rid, repl_root, certify_all, original_task ? 1 : 0);
mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
mod.mod_type = (char *)type_replicaAbortCleanRUV;
@@ -2711,8 +2722,6 @@ delete_cleaned_rid_config(cleanruv_data *clean_data)
Slapi_Entry **entries = NULL;
LDAPMod *mods[2];
LDAPMod mod;
- struct berval *vals[5] = {0, 0, 0, 0, 0}; /* maximum of 4 tasks */
- struct berval val[5];
char *iter = NULL;
char *dn = NULL;
int i, ii;
@@ -2759,7 +2768,6 @@ delete_cleaned_rid_config(cleanruv_data *clean_data)
for (i = 0; entries[i] != NULL; i++) {
char **attr_val = slapi_entry_attr_get_charray(entries[i], type_replicaCleanRUV);
char *edn = slapi_entry_get_dn(entries[i]);
- int count = 0;
for (ii = 0; attr_val && attr_val[ii] && i < 5; ii++) {
/* make a copy to retain the full value after toking */
@@ -2767,45 +2775,35 @@ delete_cleaned_rid_config(cleanruv_data *clean_data)
rid = atoi(ldap_utf8strtok_r(attr_val[ii], ":", &iter));
if (rid == clean_data->rid) {
- val[count].bv_len = strlen(aval);
- val[count].bv_val = aval;
- vals[count] = &val[count];
- count++;
- } else {
- slapi_ch_free_string(&aval);
+ struct berval *vals[2];
+ struct berval val[1];
+ val[0].bv_len = strlen(aval);
+ val[0].bv_val = aval;
+ vals[0] = &val[0];
+ vals[1] = NULL;
+
+ mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
+ mod.mod_type = (char *)type_replicaCleanRUV;
+ mod.mod_bvalues = vals;
+ mods[0] = &mod;
+ mods[1] = NULL;
+
+ modpb = slapi_pblock_new();
+ slapi_modify_internal_set_pb(modpb, edn, mods, NULL, NULL,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modify_internal_pb(modpb);
+ slapi_pblock_get(modpb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ slapi_pblock_destroy(modpb);
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
+ cleanruv_log(clean_data->task, clean_data->rid, CLEANALLRUV_ID, SLAPI_LOG_ERR,
+ "delete_cleaned_rid_config - Failed to remove task data from (%s) error (%d), rid (%d)",
+ edn, rc, clean_data->rid);
+ goto bail;
+ }
}
+ slapi_ch_free_string(&aval);
}
slapi_ch_array_free(attr_val);
-
- /*
- * Now delete the attribute
- */
- vals[4] = NULL;
- mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
- mod.mod_type = (char *)type_replicaCleanRUV;
- mod.mod_bvalues = vals;
- mods[0] = &mod;
- mods[1] = NULL;
-
- modpb = slapi_pblock_new();
- slapi_modify_internal_set_pb(modpb, edn, mods, NULL, NULL,
- repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
- slapi_modify_internal_pb(modpb);
- slapi_pblock_get(modpb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
- slapi_pblock_destroy(modpb);
-
- /* free the attr vals */
- for (ii = 0; ii < count; ii++) {
- slapi_ch_free_string(&val[ii].bv_val);
- }
-
- if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT) {
- cleanruv_log(clean_data->task, clean_data->rid, CLEANALLRUV_ID, SLAPI_LOG_ERR,
- "delete_cleaned_rid_config - Failed to remove task data "
- "from (%s) error (%d), rid (%d)",
- edn, rc, clean_data->rid);
- goto bail;
- }
}
}
}
@@ -2870,7 +2868,9 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb __attribute__((unused)),
Replica *replica;
ReplicaId rid = -1;
Object *r;
+ PRBool original_task = PR_TRUE;
const char *certify_all;
+ const char *orig_val;
const char *base_dn;
const char *rid_str;
char *ridstr = NULL;
@@ -2986,8 +2986,9 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb __attribute__((unused)),
* Stop the cleaning, and delete the rid
*/
replica = (Replica *)object_get_data(r);
- add_aborted_rid(rid, replica, (char *)base_dn);
+ add_aborted_rid(rid, replica, (char *)base_dn, (char *)certify_all, original_task);
stop_ruv_cleaning();
+
/*
* Prepare the abort struct and fire off the thread
*/
@@ -2998,6 +2999,11 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb __attribute__((unused)),
rc = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
+ if ((orig_val = slapi_fetch_attr(e, "replica-original-task", 0)) != NULL) {
+ if (!strcasecmp(orig_val, "0")) {
+ original_task = PR_FALSE;
+ }
+ }
data->repl_obj = r; /* released in replica_abort_task_thread() */
data->replica = replica;
data->task = task;
@@ -3006,7 +3012,7 @@ replica_cleanall_ruv_abort(Slapi_PBlock *pb __attribute__((unused)),
data->repl_root = slapi_ch_strdup(base_dn);
data->sdn = NULL;
data->certify = slapi_ch_strdup(certify_all);
- data->original_task = PR_TRUE;
+ data->original_task = original_task;
thread = PR_CreateThread(PR_USER_THREAD, replica_abort_task_thread,
(void *)data, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
@@ -3069,8 +3075,8 @@ replica_abort_task_thread(void *arg)
}
if (data->replica == NULL && data->repl_obj) {
data->replica = (Replica *)object_get_data(data->repl_obj);
+ release_it = 1;
}
- release_it = 1;
}
/*
@@ -3148,11 +3154,11 @@ done:
/*
* Clean up the config
*/
- delete_aborted_rid(data->replica, data->rid, data->repl_root, 1); /* delete just the config, leave rid in memory */
+ delete_aborted_rid(data->replica, data->rid, data->repl_root, data->certify, data->original_task, 1); /* delete just the config, leave rid in memory */
if (strcasecmp(data->certify, "yes") == 0) {
check_replicas_are_done_aborting(data);
}
- delete_aborted_rid(data->replica, data->rid, data->repl_root, 0); /* remove the in-memory aborted rid */
+ delete_aborted_rid(data->replica, data->rid, data->repl_root, data->certify, data->original_task, 0); /* remove the in-memory aborted rid */
if (rc == 0) {
cleanruv_log(data->task, data->rid, ABORT_CLEANALLRUV_ID, SLAPI_LOG_INFO, "Successfully aborted task for rid(%d)", data->rid);
} else {
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
index 68e2544..b49cb8c 100644
--- a/ldap/servers/plugins/replication/repl_extop.c
+++ b/ldap/servers/plugins/replication/repl_extop.c
@@ -1416,7 +1416,7 @@ multimaster_extop_abort_cleanruv(Slapi_PBlock *pb)
/*
* Set the aborted rid and stop the cleaning
*/
- add_aborted_rid(rid, r, repl_root);
+ add_aborted_rid(rid, r, repl_root, data->certify, data->original_task);
stop_ruv_cleaning();
/*
* Send out the extended ops to the replicas
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 6e223fe..025ffcb 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -379,17 +379,15 @@ slapi_task_status_changed(Slapi_Task *task)
int ttl;
time_t expire;
- e = get_internal_entry(pb, task->task_dn);
- if (e == NULL)
- return;
- ttl = atoi(slapi_fetch_attr(e, "ttl", DEFAULT_TTL));
- if (ttl > (24*3600))
- ttl = (24*3600); /* be reasonable, allow to check task status not longer than one day */
- expire = time(NULL) + ttl;
- task->task_flags |= SLAPI_TASK_DESTROYING;
- /* queue an event to destroy the state info */
- slapi_eq_once(destroy_task, (void *)task, expire);
-
+ if ((e = get_internal_entry(pb, task->task_dn))) {
+ ttl = atoi(slapi_fetch_attr(e, "ttl", DEFAULT_TTL));
+ if (ttl > (24*3600))
+ ttl = (24*3600); /* be reasonable, allow to check task status not longer than one day */
+ expire = time(NULL) + ttl;
+ task->task_flags |= SLAPI_TASK_DESTROYING;
+ /* queue an event to destroy the state info */
+ slapi_eq_once(destroy_task, (void *)task, expire);
+ }
slapi_free_search_results_internal(pb);
slapi_pblock_destroy(pb);
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years
[389-ds-base] branch master updated: Fix typo from: Issue 49915 - Add regression test
by pagure@pagure.io
This is an automated email from the git hooks/post-receive script.
mhonek 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 78f8c17 Fix typo from: Issue 49915 - Add regression test
78f8c17 is described below
commit 78f8c17a60ef311b641896da4a61d55d29f56c36
Author: Matúš Honěk <mhonek(a)redhat.com>
AuthorDate: Fri Apr 5 14:40:18 2019 +0200
Fix typo from: Issue 49915 - Add regression test
Fixes commit 0319ec02a.
Relates https://pagure.io/389-ds-base/pull-request/50320
---
dirsrvtests/tests/suites/replication/regression_test.py | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/dirsrvtests/tests/suites/replication/regression_test.py b/dirsrvtests/tests/suites/replication/regression_test.py
index 747d358..d7acd05 100644
--- a/dirsrvtests/tests/suites/replication/regression_test.py
+++ b/dirsrvtests/tests/suites/replication/regression_test.py
@@ -622,18 +622,18 @@ def test_online_reinit_may_hang(topo_with_sigkill):
3. Import should be successful
4. Server should not hang and consume 100% CPU
"""
- M1 = topo_with_sigkill.ms["master1"]
- M2 = topo_with_sigkill.ms["master2"]
+ M1 = topo_with_sigkill.ms["master1"]
+ M2 = topo_with_sigkill.ms["master2"]
M1.stop()
ldif_file = '/tmp/master1.ldif'
- M1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX],
- excludeSuffixes=None, repl_data=True,
- outputfile=ldif_file, encrypt=False)
+ M1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX],
+ excludeSuffixes=None, repl_data=True,
+ outputfile=ldif_file, encrypt=False)
_move_ruv(ldif_file)
M1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file)
M1.start()
# After this server may hang
- agmt = Agreements(M1).list()[0]:
+ agmt = Agreements(M1).list()[0]
agmt.begin_reinit()
(done, error) = agmt.wait_reinit()
assert done is True
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years
[389-ds-base] branch 389-ds-base-1.3.9 updated: Ticket 50028 - ds-replcheck -y option throws usage 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.3.9
in repository 389-ds-base.
The following commit(s) were added to refs/heads/389-ds-base-1.3.9 by this push:
new 2671222 Ticket 50028 - ds-replcheck -y option throws usage error
2671222 is described below
commit 267122260e13efa78dd3e27aae0fb3b70867d9f7
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Thu Apr 4 12:43:13 2019 -0400
Ticket 50028 - ds-replcheck -y option throws usage error
Description: Using the password file option (-y) causes
a usage error to occur. The arg validation
needs to properly check for this option.
https://pagure.io/389-ds-base/issue/50028
Reviewed by: mreynolds(one line commit rule)
---
ldap/admin/src/scripts/ds-replcheck | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ldap/admin/src/scripts/ds-replcheck b/ldap/admin/src/scripts/ds-replcheck
index f482406..e18465d 100755
--- a/ldap/admin/src/scripts/ds-replcheck
+++ b/ldap/admin/src/scripts/ds-replcheck
@@ -1209,7 +1209,7 @@ def main():
elif (args.mldif is None and
(args.suffix is None or
args.binddn is None or
- (args.bindpw is None and args.prompt is False) or
+ (args.bindpw is None and (args.prompt is False and args.pass_file is None)) or
args.murl is None or
args.rurl is None)):
print("\n-------> Missing required options for online mode!\n")
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50303 - Add task creation date to task data
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 73d18c8 Ticket 50303 - Add task creation date to task data
73d18c8 is described below
commit 73d18c8e8979679d8aaf7021e78133a75fd40eea
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Wed Mar 27 11:03:07 2019 -0400
Ticket 50303 - Add task creation date to task data
Description: Add a new attribute to the slapi task entry containing
the start date. This provides a nice convenience without
having to change LDAP clients.
https://pagure.io/389-ds-base/issue/50303
Reviewed by: firstyear & spichugi(Thanks!)
(cherry picked from commit 78003de289556ca6cdbe81fd200f80f4e8f69cbb)
---
dirsrvtests/tests/suites/basic/basic_test.py | 44 ++++++++++++++++------------
ldap/schema/02common.ldif | 10 ++++++-
ldap/servers/slapd/slap.h | 6 ++--
ldap/servers/slapd/task.c | 7 ++++-
4 files changed, 43 insertions(+), 24 deletions(-)
diff --git a/dirsrvtests/tests/suites/basic/basic_test.py b/dirsrvtests/tests/suites/basic/basic_test.py
index 50b5dc0..271f905 100644
--- a/dirsrvtests/tests/suites/basic/basic_test.py
+++ b/dirsrvtests/tests/suites/basic/basic_test.py
@@ -244,28 +244,32 @@ def test_basic_import_export(topology_st, import_example_ldif):
log.info('Running test_basic_import_export...')
- tmp_dir = '/tmp'
-
#
# Test online/offline LDIF imports
#
topology_st.standalone.start()
# Generate a test ldif (50k entries)
+ log.info("Generating LDIF...")
ldif_dir = topology_st.standalone.get_ldif_dir()
import_ldif = ldif_dir + '/basic_import.ldif'
dbgen(topology_st.standalone, 50000, import_ldif, DEFAULT_SUFFIX)
# Online
- try:
- topology_st.standalone.tasks.importLDIF(suffix=DEFAULT_SUFFIX,
- input_file=import_ldif,
- args={TASK_WAIT: True})
- except ValueError:
- log.fatal('test_basic_import_export: Online import failed')
- assert False
+ log.info("Importing LDIF online...")
+ r = ImportTask(topology_st.standalone)
+ r.import_suffix_from_ldif(ldiffile=import_ldif, suffix=DEFAULT_SUFFIX)
+
+ # Good as place as any to quick test the task has some expected attributes
+ assert r.present('nstaskcreated')
+ assert r.present('nstasklog')
+ assert r.present('nstaskcurrentitem')
+ assert r.present('nstasktotalitems')
+
+ r.wait()
# Offline
+ log.info("Importing LDIF offline...")
topology_st.standalone.stop()
if not topology_st.standalone.ldif2db(DEFAULT_BENAME, None, None, None, import_ldif):
log.fatal('test_basic_import_export: Offline import failed')
@@ -277,16 +281,15 @@ def test_basic_import_export(topology_st, import_example_ldif):
#
# Online export
+ log.info("Exporting LDIF online...")
export_ldif = ldif_dir + '/export.ldif'
- exportTask = Tasks(topology_st.standalone)
- try:
- args = {TASK_WAIT: True}
- exportTask.exportLDIF(DEFAULT_SUFFIX, None, export_ldif, args)
- except ValueError:
- log.fatal('test_basic_import_export: Online export failed')
- assert False
+
+ r = ExportTask(topology_st.standalone)
+ r.export_suffix_to_ldif(ldiffile=export_ldif, suffix=DEFAULT_SUFFIX)
+ r.wait()
# Offline export
+ log.info("Exporting LDIF offline...")
topology_st.standalone.stop()
if not topology_st.standalone.db2ldif(DEFAULT_BENAME, (DEFAULT_SUFFIX,),
None, None, None, export_ldif):
@@ -298,6 +301,7 @@ def test_basic_import_export(topology_st, import_example_ldif):
#
# Cleanup - Import the Example LDIF for the other tests in this suite
#
+ log.info("Restore datrabase, import initial LDIF...")
ldif = '%s/dirsrv/data/Example.ldif' % topology_st.standalone.get_data_dir()
import_ldif = topology_st.standalone.get_ldif_dir() + "/Example.ldif"
shutil.copyfile(ldif, import_ldif)
@@ -366,6 +370,7 @@ def test_basic_backup(topology_st, import_example_ldif):
log.info('test_basic_backup: PASSED')
+
def test_basic_db2index(topology_st, import_example_ldif):
"""Assert db2index can operate correctly.
@@ -902,7 +907,7 @@ def create_users(topology_st):
log.info('Adding 5 test users')
for name in user_names:
- user = users.create(properties={
+ users.create(properties={
'uid': name,
'sn': name,
'cn': name,
@@ -1020,6 +1025,7 @@ def test_connection_buffer_size(topology_st):
with pytest.raises(ldap.OPERATIONS_ERROR):
topology_st.standalone.config.replace('nsslapd-connection-buffer', value)
+
@pytest.mark.bz1637439
def test_critical_msg_on_empty_range_idl(topology_st):
"""Doing a range index lookup should not report a critical message even if IDL is empty
@@ -1092,6 +1098,7 @@ def test_critical_msg_on_empty_range_idl(topology_st):
# Step 5
assert not topology_st.standalone.searchErrorsLog('CRIT - list_candidates - NULL idl was recieved from filter_candidates_ext.')
+
def audit_pattern_found(server, log_pattern):
file_obj = open(server.ds_paths.audit_log, "r")
@@ -1107,6 +1114,7 @@ def audit_pattern_found(server, log_pattern):
return found
+
@pytest.mark.ds50026
def test_ticketldbm_audit(topology_st):
"""When updating LDBM config attributes, those attributes/values are not listed
@@ -1198,5 +1206,3 @@ if __name__ == '__main__':
# -s for DEBUG mode
CURRENT_FILE = os.path.realpath(__file__)
pytest.main("-s %s" % CURRENT_FILE)
-
-
diff --git a/ldap/schema/02common.ldif b/ldap/schema/02common.ldif
index 62e77a7..23d38f7 100644
--- a/ldap/schema/02common.ldif
+++ b/ldap/schema/02common.ldif
@@ -137,6 +137,13 @@ attributeTypes: ( 2.16.840.1.113730.3.1.3023 NAME 'nsViewFilter' DESC 'Netscape
attributeTypes: ( 2.16.840.1.113730.3.1.2063 NAME 'nsEncryptionAlgorithm' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
attributeTypes: ( 2.16.840.1.113730.3.1.2094 NAME 'nsslapd-parent-suffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' )
attributeTypes: ( 2.16.840.1.113730.3.1.2401 NAME 'ConflictCSN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2085 NAME 'isReplicated' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2354 NAME 'nsTaskLog' DESC 'Slapi Task log' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2355 NAME 'nsTaskStatus' DESC 'Slapi Task status' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2356 NAME 'nsTaskExitCode' DESC 'Slapi Task exit code' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2357 NAME 'nsTaskCurrentItem' DESC 'Slapi Task item' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2358 NAME 'nsTaskTotalItems' DESC 'Slapi Task total items' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2359 NAME 'nsTaskCreated' DESC 'Slapi Task creation date' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE X-ORIGIN '389 Directory Server' )
#
# objectclasses:
#
@@ -169,4 +176,5 @@ objectClasses: ( 2.16.840.1.113730.3.2.503 NAME 'nsDSWindowsReplicationAgreement
objectClasses: ( 2.16.840.1.113730.3.2.128 NAME 'costemplate' DESC 'Netscape defined objectclass' SUP top MAY ( cn $ cospriority ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.304 NAME 'nsView' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsViewFilter $ description ) X-ORIGIN 'Netscape Directory Server' )
objectClasses: ( 2.16.840.1.113730.3.2.316 NAME 'nsAttributeEncryption' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsEncryptionAlgorithm ) X-ORIGIN 'Netscape Directory Server' )
-attributeTypes: ( 2.16.840.1.113730.3.1.2085 NAME 'isReplicated' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.335 NAME 'nsSlapiTask' DESC 'Slapi_Task objectclass' SUP top MUST ( cn ) MAY ( ttl $ nsTaskLog $ nsTaskStatus $ nsTaskExitCode $ nsTaskCurrentItem $ nsTaskTotalItems $ nsTaskCreated ) X-ORIGIN '389 Directory Server' )
+
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 6b80b3e..c7becf5 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -1723,13 +1723,13 @@ struct slapi_task
int task_flags; /* (see above) */
char *task_status; /* transient status info */
char *task_log; /* appended warnings, etc */
+ char task_date[SLAPI_TIMESTAMP_BUFSIZE]; /* Date/time when task was created */
void *task_private; /* allow opaque data to be stashed in the task */
TaskCallbackFn cancel; /* task has been cancelled by user */
TaskCallbackFn destructor; /* task entry is being destroyed */
int task_refcount;
- void *origin_plugin; /* If this is a plugin create task, store the plugin object */
- PRLock *task_log_lock; /* To protect task_log to be realloced if
- it's in use */
+ void *origin_plugin; /* If this is a plugin create task, store the plugin object */
+ PRLock *task_log_lock; /* To protect task_log to be realloced if it's in use */
} slapi_task;
/* End of interface to support online tasks **********************************/
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index b42e872..6e223fe 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -45,6 +45,7 @@ static int shutting_down = 0;
#define TASK_EXITCODE_NAME "nsTaskExitCode"
#define TASK_PROGRESS_NAME "nsTaskCurrentItem"
#define TASK_WORK_NAME "nsTaskTotalItems"
+#define TASK_DATE_NAME "nsTaskCreated"
#define DEFAULT_TTL "3600" /* seconds */
#define TASK_SYSCONFIG_FILE_ATTR "sysconfigfile" /* sysconfig reload task file attr */
@@ -347,6 +348,7 @@ slapi_task_status_changed(Slapi_Task *task)
sprintf(s3, "%d", task->task_work);
NEXTMOD(TASK_PROGRESS_NAME, s2);
NEXTMOD(TASK_WORK_NAME, s3);
+ NEXTMOD(TASK_DATE_NAME, task->task_date);
/* only add the exit code when the job is done */
if ((task->task_state == SLAPI_TASK_FINISHED) ||
(task->task_state == SLAPI_TASK_CANCELLED)) {
@@ -604,6 +606,9 @@ new_task(const char *rawdn, void *plugin)
return NULL;
}
+ /* Set the task creation time */
+ slapi_timestamp_utc_hr(task->task_date, SLAPI_TIMESTAMP_BUFSIZE);
+
/* Now take our lock to setup everything correctly. */
PR_Lock(task->task_log_lock);
@@ -687,7 +692,7 @@ destroy_task(time_t when, void *arg)
slapi_delete_internal_pb(pb);
slapi_pblock_destroy(pb);
- slapi_ch_free((void **)&task->task_dn);
+ slapi_ch_free_string(&task->task_dn);
slapi_ch_free((void **)&task);
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years
[389-ds-base] branch 389-ds-base-1.4.0 updated: Ticket 50240 - Improve task logging
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 593a718 Ticket 50240 - Improve task logging
593a718 is described below
commit 593a7180538d2da5a4ad731aebb85a64af7c50c0
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Sun Feb 24 12:57:19 2019 -0500
Ticket 50240 - Improve task logging
Description: Improve the updates to the task's log attribute when
errors occur. Previously we were not recording the
reason for most failures during db2ldif, ldif2db, and
db2index.
https://pagure.io/389-ds-base/issue/50240
Reviewed by: ?
---
ldap/servers/slapd/back-ldbm/ldif2ldbm.c | 331 ++++++++++++++-----------------
1 file changed, 151 insertions(+), 180 deletions(-)
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
index 2266ea9..60437f1 100644
--- a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -664,11 +664,13 @@ ldbm_back_ldif2ldbm(Slapi_PBlock *pb)
{
struct ldbminfo *li;
ldbm_instance *inst = NULL;
+ Slapi_Task *task = NULL;
char *instance_name;
int ret, task_flags;
slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li);
slapi_pblock_get(pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name);
+ slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task);
/* BEGIN complex dependencies of various initializations. */
/* hopefully this will go away once import is not run standalone... */
@@ -698,6 +700,7 @@ ldbm_back_ldif2ldbm(Slapi_PBlock *pb)
/* Find the instance that the ldif2db will be done on. */
inst = ldbm_instance_find_by_name(li, instance_name);
if (NULL == inst) {
+ slapi_task_log_notice(task, "Unknown ldbm instance %s", instance_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm", "Unknown ldbm instance %s\n",
instance_name);
return -1;
@@ -705,6 +708,9 @@ ldbm_back_ldif2ldbm(Slapi_PBlock *pb)
/* check if an import/restore is already ongoing... */
if ((instance_set_busy(inst) != 0)) {
+ slapi_task_log_notice(task,
+ "Backend instance '%s' already in the middle of another task",
+ inst->inst_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm", "ldbm: '%s' is already in the middle of "
"another task and cannot be disturbed.\n",
inst->inst_name);
@@ -713,19 +719,27 @@ ldbm_back_ldif2ldbm(Slapi_PBlock *pb)
uint64_t refcnt;
refcnt = slapi_counter_get_value(inst->inst_ref_count);
if (refcnt > 0) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm", "ldbm: '%s' there are %" PRIu64 " pending operation(s)."
+ slapi_task_log_notice(task,
+ "Backend instance '%s': there are %" PRIu64 " pending operation(s)."
+ " Import can not proceed until they are completed.\n",
+ inst->inst_name, refcnt);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldif2ldbm",
+ "ldbm: '%s' there are %" PRIu64 " pending operation(s)."
" Import can not proceed until they are completed.\n",
- inst->inst_name,
- refcnt);
+ inst->inst_name, refcnt);
instance_set_not_busy(inst);
return -1;
}
}
if ((task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE)) {
- if (dblayer_import_file_init(inst)) {
+ if ((ret = dblayer_import_file_init(inst))) {
+ slapi_task_log_notice(task,
+ "Backend instance '%s' Failed to write import file, error %d: %s",
+ inst->inst_name, ret, slapd_pr_strerror(ret));
slapi_log_err(SLAPI_LOG_ERR,
- "ldbm_back_ldif2ldbm", "Failed to write import file\n");
+ "ldbm_back_ldif2ldbm", "%s: Failed to write import file, error %d: %s\n",
+ inst->inst_name, ret, slapd_pr_strerror(ret));
return -1;
}
}
@@ -1157,6 +1171,7 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags);
slapi_pblock_get(pb, SLAPI_DB2LDIF_DECRYPT, &decrypt);
slapi_pblock_get(pb, SLAPI_DB2LDIF_SERVER_RUNNING, &server_running);
+ slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task);
run_from_cmdline = (task_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE);
dump_replica = slapi_pblock_get_ldif_dump_replica(pb);
@@ -1195,7 +1210,8 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
slapi_pblock_get(pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name);
inst = ldbm_instance_find_by_name(li, instance_name);
if (NULL == inst) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Unknown backend instance %s\n",
+ slapi_task_log_notice(task, "Unknown backend instance: %s", instance_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Unknown backend instance: %s\n",
instance_name);
return_value = -1;
goto bye;
@@ -1203,7 +1219,8 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
/* [605974] command db2ldif should not be able to run when on-line
* import is running */
if (dblayer_in_import(inst)) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Backend instance %s is busy\n",
+ slapi_task_log_notice(task, "Backend instance '%s' is busy", instance_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Backend instance '%s' is busy\n",
instance_name);
return_value = -1;
goto bye;
@@ -1215,19 +1232,24 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
} else {
slapi_pblock_get(pb, SLAPI_BACKEND, &be);
if (!be) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "No backend\n");
+ slapi_task_log_notice(task, "No backend for: %s", instance_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "No backend for: %s\n", instance_name);
return_value = -1;
goto bye;
}
inst = (ldbm_instance *)be->be_instance_info;
if (!inst) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Unknown backend instance\n");
+ slapi_task_log_notice(task, "Unknown backend instance: %s",instance_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Unknown backend instance: %s\n",instance_name);
return_value = -1;
goto bye;
}
/* check if an import/restore is already ongoing... */
if (instance_set_busy(inst) != 0) {
+ slapi_task_log_notice(task,
+ "Backend instance '%s' is already in the middle of another task and cannot be disturbed.",
+ inst->inst_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Backend instance '%s' is already in the middle"
" of another task and cannot be disturbed.\n",
inst->inst_name);
@@ -1236,8 +1258,6 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
}
}
- slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task);
-
ldbm_back_fetch_incl_excl(pb, &include_suffix, &exclude_suffix);
str2entry_options = (dump_replica ? 0 : SLAPI_STR2ENTRY_TOMBSTONE_CHECK);
@@ -1272,6 +1292,7 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
options |= SLAPI_DUMP_STATEINFO;
if (fname == NULL) {
+ slapi_task_log_notice(task, "%s: no LDIF filename supplied.", inst->inst_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "db2ldif: no LDIF filename supplied\n");
return_value = -1;
goto bye;
@@ -1293,8 +1314,12 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
}
if (fd < 0) {
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "db2ldif: can't open %s: %d (%s) while running as user \"%s\"\n",
- fname, errno, dblayer_strerror(errno), slapdFrontendConfig->localuserinfo->pw_name);
+ slapi_task_log_notice(task,
+ "Backend %s: can't open %s: %d (%s) while running as user \"%s\"",
+ inst->inst_name, fname, errno, dblayer_strerror(errno), slapdFrontendConfig->localuserinfo->pw_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif",
+ "db2ldif: %s: can't open %s: %d (%s) while running as user \"%s\"\n",
+ inst->inst_name, fname, errno, dblayer_strerror(errno), slapdFrontendConfig->localuserinfo->pw_name);
return_value = -1;
goto bye;
}
@@ -1304,13 +1329,19 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
if (we_start_the_backends) {
if (0 != dblayer_start(li, DBLAYER_EXPORT_MODE)) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "db2ldif: Failed to init database\n");
+ slapi_task_log_notice(task, "Failed to init database for: %s", inst->inst_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif",
+ "db2ldif: Failed to init database: %s\n",
+ inst->inst_name);
return_value = -1;
goto bye;
}
/* dblayer_instance_start will init the id2entry index. */
if (0 != dblayer_instance_start(be, DBLAYER_EXPORT_MODE)) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "db2ldif: Failed to init instance\n");
+ slapi_task_log_notice(task, "Failed to start database instance: %s", inst->inst_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif",
+ "db2ldif: Failed to start database instance: %s\n",
+ inst->inst_name);
return_value = -1;
goto bye;
}
@@ -1321,7 +1352,12 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
get_ids_from_disk(be);
if (((dblayer_get_id2entry(be, &db)) != 0) || (db == NULL)) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "Could not open/create id2entry\n");
+ slapi_task_log_notice(task,
+ "Backend instance '%s' Unable to open/create database(id2entry)",
+ inst->inst_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif",
+ "Could not open/create id2entry for: %s\n",
+ inst->inst_name);
return_value = -1;
goto bye;
}
@@ -1341,9 +1377,12 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
/* get a cursor to we can walk over the table */
return_value = db->cursor(db, NULL, &dbc, 0);
if (0 != return_value || NULL == dbc) {
+ slapi_task_log_notice(task,
+ "Backend instance '%s' Failed to get database cursor: %s (%d)",
+ inst->inst_name, dblayer_strerror(return_value), return_value);
slapi_log_err(SLAPI_LOG_ERR,
- "ldbm_back_ldbm2ldif", "Failed to get cursor for db2ldif; %s (%d)\n",
- dblayer_strerror(return_value), return_value);
+ "ldbm_back_ldbm2ldif", "Backend instance '%s' Failed to get cursor for db2ldif: %s (%d)\n",
+ inst->inst_name, dblayer_strerror(return_value), return_value);
return_value = -1;
goto bye;
}
@@ -1367,8 +1406,8 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
if (err) {
/* most likely, indexes are bad. */
slapi_log_err(SLAPI_LOG_ERR,
- "ldbm_back_ldbm2ldif", "Failed to fetch subtree lists (error %d) %s\n",
- err, dblayer_strerror(err));
+ "ldbm_back_ldbm2ldif", "Backend %s: Failed to fetch subtree lists (error %d) %s\n",
+ inst->inst_name, err, dblayer_strerror(err));
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2ldif", "Possibly the entrydn/entryrdn or ancestorid index is "
"corrupted or does not exist.\n");
@@ -1438,10 +1477,12 @@ ldbm_back_ldbm2ldif(Slapi_PBlock *pb)
break;
}
if (return_value) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif", "db2ldif: failed to read "
- "entry %lu, err %d\n",
- (u_long)idl->b_ids[idindex],
- return_value);
+ slapi_task_log_notice(task, "Backend %s: Failed to read entry %lu, err %d\n",
+ inst->inst_name, (u_long)idl->b_ids[idindex], return_value);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2ldif",
+ "db2ldif: Backend %s: failed to read entry %lu, err %d\n",
+ inst->inst_name, (u_long)idl->b_ids[idindex],
+ return_value);
return_value = -1;
break;
}
@@ -1805,10 +1846,7 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
inst = ldbm_instance_find_by_name(li, instance_name);
if (NULL == inst) {
- if (task) {
- slapi_task_log_notice(task, "Unknown ldbm instance %s",
- instance_name);
- }
+ slapi_task_log_notice(task, "Unknown ldbm instance %s", instance_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "Unknown ldbm instance %s\n",
instance_name);
return return_value;
@@ -1824,14 +1862,16 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
ldbm_config_internal_set(li, CONFIG_DB_TRANSACTION_LOGGING, "off");
if (0 != dblayer_start(li, DBLAYER_INDEX_MODE)) {
+ slapi_task_log_notice(task, "Failed to init database: %s", instance_name);
slapi_log_err(SLAPI_LOG_ERR,
- "ldbm2index", "Failed to init database\n");
+ "ldbm2index", "Failed to init database: %s\n", instance_name);
return return_value;
}
/* dblayer_instance_start will init the id2entry index. */
if (0 != dblayer_instance_start(be, DBLAYER_INDEX_MODE)) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "db2ldif: Failed to init instance\n");
+ slapi_task_log_notice(task, "Failed to start instance: %s", instance_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "db2ldif: Failed to start instance\n");
return return_value;
}
@@ -1841,6 +1881,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
/* make sure no other tasks are going, and set the backend readonly */
if (instance_set_busy_and_readonly(inst) != 0) {
+ slapi_task_log_notice(task,
+ "%s: is already in the middle of another task and cannot be disturbed.",
+ inst->inst_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "ldbm: '%s' is already in the middle of "
"another task and cannot be disturbed.\n",
inst->inst_name);
@@ -1848,15 +1891,22 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
}
if (((dblayer_get_id2entry(be, &db)) != 0) || (db == NULL)) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "Could not open/create id2entry\n");
+ slapi_task_log_notice(task,
+ "%s: Could not open/create database (id2entry)",
+ inst->inst_name);
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "Could not open/create database(id2entry)\n");
goto err_min;
}
/* get a cursor to we can walk over the table */
rc = db->cursor(db, NULL, &dbc, 0);
if (0 != rc) {
+ slapi_task_log_notice(task,
+ "%s: Failed to get database cursor for ldbm2index",
+ inst->inst_name);
slapi_log_err(SLAPI_LOG_ERR,
- "ldbm_back_ldbm2index", "Failed to get cursor for ldbm2index\n");
+ "ldbm_back_ldbm2index", "%s: Failed to get cursor for ldbm2index\n",
+ inst->inst_name);
goto err_min;
}
@@ -1873,9 +1923,11 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_ch_free(&(data.data));
isfirst = 1;
} else {
+ slapi_task_log_notice(task, "%s: Failed to seek within id2entry (BAD %d)",
+ inst->inst_name, return_value);
slapi_log_err(SLAPI_LOG_ERR,
- "ldbm_back_ldbm2index", "Failed to seek within id2entry (BAD %d)\n",
- return_value);
+ "ldbm_back_ldbm2index", "%s: Failed to seek within id2entry (BAD %d)\n",
+ inst->inst_name, return_value);
goto err_out;
}
@@ -1901,29 +1953,21 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
/* the ai was added above, if it didn't already exist */
PR_ASSERT(ai != NULL);
if (strcasecmp(attrs[i] + 1, LDBM_ANCESTORID_STR) == 0) {
- if (task) {
- slapi_task_log_notice(task, "%s: Indexing %s",
- inst->inst_name, LDBM_ANCESTORID_STR);
- }
+ slapi_task_log_notice(task, "%s: Indexing %s",
+ inst->inst_name, LDBM_ANCESTORID_STR);
slapi_log_err(SLAPI_LOG_INFO, "ldbm_back_ldbm2index", "%s: Indexing %s\n",
inst->inst_name, LDBM_ANCESTORID_STR);
index_ext |= DB2INDEX_ANCESTORID;
} else if (strcasecmp(attrs[i] + 1, LDBM_ENTRYRDN_STR) == 0) {
if (entryrdn_get_switch()) { /* subtree-rename: on */
- if (task) {
- slapi_task_log_notice(task, "%s: Indexing %s",
- inst->inst_name, LDBM_ENTRYRDN_STR);
- }
+ slapi_task_log_notice(task, "%s: Indexing %s",
+ inst->inst_name, LDBM_ENTRYRDN_STR);
slapi_log_err(SLAPI_LOG_INFO, "ldbm_back_ldbm2index", "%s: Indexing %s\n",
inst->inst_name, LDBM_ENTRYRDN_STR);
index_ext |= DB2INDEX_ENTRYRDN;
} else {
- if (task) {
- slapi_task_log_notice(task,
- "%s: Requested to index %s, but %s is off",
- inst->inst_name, LDBM_ENTRYRDN_STR,
- CONFIG_ENTRYRDN_SWITCH);
- }
+ slapi_task_log_notice(task, "%s: Requested to index %s, but %s is off",
+ inst->inst_name, LDBM_ENTRYRDN_STR, CONFIG_ENTRYRDN_SWITCH);
slapi_log_err(SLAPI_LOG_WARNING,
"ldbm_back_ldbm2index", "%s: Requested to index %s, but %s is off\n",
inst->inst_name, LDBM_ENTRYRDN_STR,
@@ -1932,12 +1976,8 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
}
} else if (strcasecmp(attrs[i] + 1, LDBM_ENTRYDN_STR) == 0) {
if (entryrdn_get_switch()) { /* subtree-rename: on */
- if (task) {
- slapi_task_log_notice(task,
- "%s: Requested to index %s, but %s is on",
- inst->inst_name, LDBM_ENTRYDN_STR,
- CONFIG_ENTRYRDN_SWITCH);
- }
+ slapi_task_log_notice(task, "%s: Requested to index %s, but %s is on",
+ inst->inst_name, LDBM_ENTRYDN_STR, CONFIG_ENTRYRDN_SWITCH);
slapi_log_err(SLAPI_LOG_WARNING,
"ldbm_back_ldbm2index", "%s: Requested to index %s, but %s is on\n",
inst->inst_name, LDBM_ENTRYDN_STR,
@@ -1946,11 +1986,8 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
} else {
charray_add(&indexAttrs, attrs[i] + 1);
ai->ai_indexmask |= INDEX_OFFLINE;
- if (task) {
- slapi_task_log_notice(task,
- "%s: Indexing attribute: %s",
- inst->inst_name, attrs[i] + 1);
- }
+ slapi_task_log_notice(task, "%s: Indexing attribute: %s",
+ inst->inst_name, attrs[i] + 1);
slapi_log_err(SLAPI_LOG_INFO,
"ldbm_back_ldbm2index", "%s: Indexing attribute: %s\n",
inst->inst_name, attrs[i] + 1);
@@ -1961,10 +1998,8 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
}
charray_add(&indexAttrs, attrs[i] + 1);
ai->ai_indexmask |= INDEX_OFFLINE;
- if (task) {
- slapi_task_log_notice(task, "%s: Indexing attribute: %s",
- inst->inst_name, attrs[i] + 1);
- }
+ slapi_task_log_notice(task, "%s: Indexing attribute: %s",
+ inst->inst_name, attrs[i] + 1);
slapi_log_err(SLAPI_LOG_INFO,
"ldbm_back_ldbm2index", "%s: Indexing attribute: %s\n",
inst->inst_name, attrs[i] + 1);
@@ -1988,10 +2023,7 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
numvlv++;
/* Get rid of the index if it already exists */
PR_Delete(vlvIndex_filename(vlvip));
- if (task) {
- slapi_task_log_notice(task, "%s: Indexing VLV: %s",
- inst->inst_name, attrs[i] + 1);
- }
+ slapi_task_log_notice(task, "%s: Indexing VLV: %s", inst->inst_name, attrs[i] + 1);
slapi_log_err(SLAPI_LOG_INFO, "ldbm_back_ldbm2index", "%s: Indexing VLV: %s\n",
inst->inst_name, attrs[i] + 1);
}
@@ -2030,12 +2062,10 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_WARNING, "ldbm_back_ldbm2index",
"%s: Attempting brute-force method instead.\n",
inst->inst_name);
- if (task) {
- slapi_task_log_notice(task,
- "ldbm_back_ldbm2index - %s: WARNING: Failed to fetch subtree lists (err %d) -- "
- "attempting brute-force method instead.",
- inst->inst_name, err);
- }
+ slapi_task_log_notice(task,
+ "%s: WARNING: Failed to fetch subtree lists (err %d) -- "
+ "attempting brute-force method instead.",
+ inst->inst_name, err);
}
} else if (ALLIDS(idl)) {
/* that's no help. */
@@ -2067,11 +2097,8 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "%s: Failed "
"to read database, errno=%d (%s)\n",
inst->inst_name, rc, dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: Failed to read database, err %d (%s)",
- inst->inst_name, rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task, "%s: Failed to read database, err %d (%s)",
+ inst->inst_name, rc, dblayer_strerror(rc));
break;
}
/* back to internal format: */
@@ -2089,15 +2116,11 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
if (DB_NOTFOUND == rc) {
break;
} else if (0 != rc) {
- slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "%s: Failed to read database, "
- "errno=%d (%s)\n",
- inst->inst_name, rc,
- dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: Failed to read database, err %d (%s)",
- inst->inst_name, rc, dblayer_strerror(rc));
- }
+ slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index",
+ "%s: Failed to read database, errno=%d (%s)\n",
+ inst->inst_name, rc, dblayer_strerror(rc));
+ slapi_task_log_notice(task, "%s: Failed to read database, err %d (%s)",
+ inst->inst_name, rc, dblayer_strerror(rc));
break;
}
temp_id = id_stored_to_internal((char *)key.data);
@@ -2251,11 +2274,8 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
if (ep->ep_entry != NULL) {
ep->ep_id = temp_id;
} else {
- if (task) {
- slapi_task_log_notice(task,
- "%s: WARNING: skipping badly formatted entry (id %lu)",
- inst->inst_name, (u_long)temp_id);
- }
+ slapi_task_log_notice(task, "%s: WARNING: skipping badly formatted entry (id %lu)",
+ inst->inst_name, (u_long)temp_id);
slapi_log_err(SLAPI_LOG_WARNING,
"ldbm_back_ldbm2index", "%s: Skipping badly formatted entry (id %lu)\n",
inst->inst_name, (u_long)temp_id);
@@ -2282,12 +2302,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index",
"%s: Failed to begin txn for update index '%s' (err %d: %s)\n",
inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task, "%s: ERROR: failed to begin txn for "
- "update index '%s' (err %d: %s)",
- inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc,
- dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to begin txn for update index '%s' (err %d: %s)",
+ inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2300,13 +2317,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index",
"%s: Failed to update index '%s' (err %d: %s)\n",
inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task, "%s: ERROR: failed to update index '%s' "
- "(err %d: %s)",
- inst->inst_name,
- SLAPI_ATTR_TOMBSTONE_CSN, rc,
- dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to update index '%s' (err %d: %s)",
+ inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
if (!run_from_cmdline) {
dblayer_txn_abort(be, &txn);
}
@@ -2319,12 +2332,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index",
"%s: Failed to commit txn for update index '%s' (err %d: %s)\n",
inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task, "%s: ERROR: failed to commit txn for "
- "update index '%s' (err %d: %s)",
- inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN,
- rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to commit txn for update index '%s' (err %d: %s)",
+ inst->inst_name, SLAPI_ATTR_TOMBSTONE_CSN, rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2374,13 +2384,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Error %d: %s\n", inst->inst_name, rc,
dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to begin txn for "
- "update index '%s' (err %d: %s)",
- inst->inst_name, indexAttrs[j], rc,
- dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to begin txn for update index '%s' (err %d: %s)",
+ inst->inst_name, indexAttrs[j], rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2397,13 +2403,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Error %d: %s\n", inst->inst_name, rc,
dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to update index '%s' "
- "(err %d: %s)",
- inst->inst_name,
- indexAttrs[j], rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to update index '%s' (err %d: %s)",
+ inst->inst_name, indexAttrs[j], rc, dblayer_strerror(rc));
if (!run_from_cmdline) {
dblayer_txn_abort(be, &txn);
}
@@ -2420,14 +2422,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Error %d: %s\n", inst->inst_name, rc,
dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to commit txn for "
- "update index '%s' "
- "(err %d: %s)",
- inst->inst_name,
- indexAttrs[j], rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to commit txn for update index '%s' (err %d: %s)",
+ inst->inst_name, indexAttrs[j], rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2452,20 +2449,15 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
if (!run_from_cmdline) {
rc = dblayer_txn_begin(be, NULL, &txn);
if (0 != rc) {
-
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Failed to begin txn for update index '%s'\n",
inst->inst_name, ai);
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Error %d: %s\n", inst->inst_name, rc,
dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to begin txn for update index '%s' "
- "(err %d: %s)",
- inst->inst_name,
- ai, rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to begin txn for update index '%s' (err %d: %s)",
+ inst->inst_name, ai, rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2486,13 +2478,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Error %d: %s\n", inst->inst_name, rc,
dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to commit txn for update index '%s' "
- "(err %d: %s)",
- inst->inst_name,
- ai, rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to commit txn for update index '%s' (err %d: %s)",
+ inst->inst_name, ai, rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2511,13 +2499,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Error %d: %s\n", inst->inst_name, rc,
dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to update index 'ancestorid' "
- "(err %d: %s)",
- inst->inst_name,
- rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to update index 'ancestorid' (err %d: %s)",
+ inst->inst_name, rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2532,12 +2516,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
inst->inst_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "%s: Error %d: %s\n",
inst->inst_name, rc, dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to begin txn for "
- "update index 'entryrdn' (err %d: %s)",
- inst->inst_name, rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to begin txn for update index 'entryrdn' (err %d: %s)",
+ inst->inst_name, rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2550,13 +2531,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
slapi_log_err(SLAPI_LOG_ERR,
"ldbm_back_ldbm2index", "%s: Error %d: %s\n", inst->inst_name, rc,
dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to update index 'entryrdn' "
- "(err %d: %s)",
- inst->inst_name,
- rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to update index 'entryrdn' (err %d: %s)",
+ inst->inst_name, rc, dblayer_strerror(rc));
if (!run_from_cmdline) {
dblayer_txn_abort(be, &txn);
}
@@ -2572,12 +2549,9 @@ ldbm_back_ldbm2index(Slapi_PBlock *pb)
inst->inst_name);
slapi_log_err(SLAPI_LOG_ERR, "ldbm_back_ldbm2index", "%s: Error %d: %s\n",
inst->inst_name, rc, dblayer_strerror(rc));
- if (task) {
- slapi_task_log_notice(task,
- "%s: ERROR: failed to commit txn for "
- "update index 'entryrdn' (err %d: %s)",
- inst->inst_name, rc, dblayer_strerror(rc));
- }
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to commit txn for update index 'entryrdn' (err %d: %s)",
+ inst->inst_name, rc, dblayer_strerror(rc));
return_value = -2;
goto err_out;
}
@@ -2860,12 +2834,9 @@ ldbm_back_upgradedb(Slapi_PBlock *pb)
"ldbm: '%s' is already in the middle of "
"another task and cannot be disturbed.\n",
inst->inst_name);
- if (task) {
- slapi_task_log_notice(task,
- "Backend '%s' is already in the middle of "
- "another task and cannot be disturbed.\n",
- inst->inst_name);
- }
+ slapi_task_log_notice(task,
+ "Backend '%s' is already in the middle of another task and cannot be disturbed.\n",
+ inst->inst_name);
/* painfully, we have to clear the BUSY flags on the
* backends we'd already marked...
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
5 years