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 e568d47 Ticket 50289 - Fix various database UI issues
e568d47 is described below
commit e568d4747127d0122d976c18aae09d31567d2bdc
Author: Mark Reynolds <mreynolds(a)redhat.com>
AuthorDate: Mon Mar 18 13:02:42 2019 -0400
Ticket 50289 - Fix various database UI issues
Description:
Fixed these issues:
-
https://bugzilla.redhat.com/show_bug.cgi?id=1664621 - backup freezes when no suffix
present
-
https://bugzilla.redhat.com/show_bug.cgi?id=1685395 - Perform Backup fails when
Backend Name is not configured
-
https://bugzilla.redhat.com/show_bug.cgi?id=1688587 - typo when restarting instance
-
https://bugzilla.redhat.com/show_bug.cgi?id=1688775 - db tree breaks when suffix
contains spaces.
-
https://bugzilla.redhat.com/show_bug.cgi?id=1688919 - backups fail with empty name
Also fixed issue where if you start an instance in UI the configuration is correctly
loaded.
https://pagure.io/389-ds-base/issue/50289
Reviewed by: spichugi(Thanks!)
---
ldap/servers/slapd/task.c | 15 ++--
src/cockpit/389-console/src/database.jsx | 32 +++++----
src/cockpit/389-console/src/ds.js | 16 ++---
src/cockpit/389-console/src/index.es6 | 11 ++-
src/cockpit/389-console/src/index.html | 1 +
.../389-console/src/lib/database/backups.jsx | 17 +++--
src/cockpit/389-console/src/plugins.jsx | 2 +-
src/cockpit/389-console/src/servers.js | 48 ++++++++-----
src/lib389/lib389/backend.py | 14 ++++
src/lib389/lib389/cli_conf/backend.py | 7 +-
src/lib389/lib389/pwpolicy.py | 84 +++++++++++-----------
11 files changed, 147 insertions(+), 100 deletions(-)
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
index 8741570..b42e872 100644
--- a/ldap/servers/slapd/task.c
+++ b/ldap/servers/slapd/task.c
@@ -1486,7 +1486,7 @@ task_backup_add(Slapi_PBlock *pb __attribute__((unused)),
Slapi_Entry *e,
Slapi_Entry *eAfter __attribute__((unused)),
int *returncode,
- char *returntext __attribute__((unused)),
+ char *returntext,
void *arg __attribute__((unused)))
{
Slapi_Backend *be = NULL;
@@ -1529,18 +1529,19 @@ task_backup_add(Slapi_PBlock *pb __attribute__((unused)),
}
slapi_ch_free_string(&cookie);
if (NULL == be || NULL == be->be_database->plg_db2archive) {
- slapi_log_err(SLAPI_LOG_ERR,
- "task_backup_add", "no db2archive function
defined.\n");
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "no db2archive function defined. There is no backend/suffix
present");
+ slapi_log_err(SLAPI_LOG_ERR, "task_backup_add", "Error:
%s\n", returntext);
*returncode = LDAP_UNWILLING_TO_PERFORM;
rv = SLAPI_DSE_CALLBACK_ERROR;
goto out;
}
if (!SLAPI_PLUGIN_IS_V3(be->be_database)) {
- slapi_log_err(SLAPI_LOG_ERR,
- "task_backup_add", "Can't perform an backup with
pre-V3 "
- "backend plugin %s\n",
- be->be_database->plg_name);
+ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Can't perform an backup with pre-V3 backend plugin %s\n",
+ be->be_database->plg_name);
+ slapi_log_err(SLAPI_LOG_ERR, "task_backup_add", "Error:
%s\n", returntext);
*returncode = LDAP_UNWILLING_TO_PERFORM;
rv = SLAPI_DSE_CALLBACK_ERROR;
goto out;
diff --git a/src/cockpit/389-console/src/database.jsx
b/src/cockpit/389-console/src/database.jsx
index ccc2c19..cbcb126 100644
--- a/src/cockpit/389-console/src/database.jsx
+++ b/src/cockpit/389-console/src/database.jsx
@@ -97,11 +97,13 @@ export class Database extends React.Component {
}
componentWillMount () {
- this.loadGlobalConfig();
- this.loadChainingConfig();
- this.loadLDIFs();
- this.loadBackups();
- this.loadSuffixList();
+ if (!this.state.loaded) {
+ this.loadGlobalConfig();
+ this.loadChainingConfig();
+ this.loadLDIFs();
+ this.loadBackups();
+ this.loadSuffixList();
+ }
}
componentDidMount() {
@@ -183,7 +185,7 @@ export class Database extends React.Component {
}), this.setState({configUpdated: 0}));
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading database configuration - ${err}`
);
@@ -269,7 +271,7 @@ export class Database extends React.Component {
), this.loadAvailableControls());
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading default chaining configuration - ${err}`
);
@@ -313,11 +315,14 @@ export class Database extends React.Component {
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-"
+ this.props.serverId + ".socket",
"backend", "get-tree",
];
- log_cmd("getTree", "Start building the suffix tree", cmd);
+ log_cmd("loadSuffixTree", "Start building the suffix tree",
cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
- let treeData = JSON.parse(content);
+ let treeData = [];
+ if (content != "") {
+ treeData = JSON.parse(content);
+ }
let basicData = [
{
text: "Global Database Configuration",
@@ -356,7 +361,6 @@ export class Database extends React.Component {
this.setState(() => ({
nodes: basicData,
node_name: current_node,
-
}), this.update_tree_nodes);
});
}
@@ -770,7 +774,7 @@ export class Database extends React.Component {
});
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading indexes for ${suffix} - ${err}`
);
@@ -924,7 +928,7 @@ export class Database extends React.Component {
});
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Error loading indexes for
${suffix} - ${err}`
);
@@ -960,7 +964,7 @@ export class Database extends React.Component {
const cmd = [
"dsctl", "-j", this.props.serverId, "backups"
];
- log_cmd("loadLDIFs", "Load Backups", cmd);
+ log_cmd("loadBackups", "Load Backups", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
@@ -995,7 +999,7 @@ export class Database extends React.Component {
});
})
.fail(err => {
- this.props.addNotification(
+ this.addNotification(
"error",
`Failed to get attributes - ${err}`
);
diff --git a/src/cockpit/389-console/src/ds.js b/src/cockpit/389-console/src/ds.js
index d309845..8d5e3dc 100644
--- a/src/cockpit/389-console/src/ds.js
+++ b/src/cockpit/389-console/src/ds.js
@@ -300,13 +300,6 @@ function popup_success(msg) {
// all the save functions for all the pages here. This is not used for modal forms
function save_all () {
save_config(); // Server Config Page
- //
- // TODO:
- // save_chaining();
- // save_chaining_suffix();
- // save_global_backend();
- // save_suffix();
- // save_security();
}
function load_repl_suffix_dropdowns() {
@@ -342,7 +335,7 @@ function load_repl_suffix_dropdowns() {
var loading_cfg = 0;
-function load_config (){
+function load_config (refresh){
// If we are currently loading config don't do it twice
if (loading_cfg == 1){
return;
@@ -409,6 +402,13 @@ function load_config (){
$("#server-config").show();
clearInterval(loading_config);
loading_cfg = 0;
+
+ if (refresh) {
+ // Reload reactJS pages by clicking dummy element
+ let reload_el = document.getElementById('reload-page');
+ reload_el.click();
+ }
+
console.log("Completed configuration initialization.");
}
}, 300);
diff --git a/src/cockpit/389-console/src/index.es6
b/src/cockpit/389-console/src/index.es6
index 7dfd433..404cbb0 100644
--- a/src/cockpit/389-console/src/index.es6
+++ b/src/cockpit/389-console/src/index.es6
@@ -14,16 +14,18 @@ function renderReactDOM(clear) {
.getElementById("select-server")
.value.replace("slapd-", "");
}
+ let d = new Date();
+ let n = d.getTime(); // might not be needed MARK
// Plugins Tab
ReactDOM.render(
- <Plugins serverId={serverIdElem} />,
+ <Plugins serverId={serverIdElem} key={n} />,
document.getElementById("plugins")
);
// Database tab
ReactDOM.render(
- <Database serverId={serverIdElem} />,
+ <Database serverId={serverIdElem} key={n} />,
document.getElementById("database")
);
}
@@ -45,10 +47,7 @@ document.addEventListener("DOMContentLoaded", function() {
.getElementById("select-server")
.addEventListener("change", renderReactWrapper);
document
- .getElementById("start-server-btn")
- .addEventListener("click", renderReactWrapper);
- document
- .getElementById("restart-server-btn")
+ .getElementById("reload-page")
.addEventListener("click", renderReactWrapper);
document
.getElementById("remove-server-btn")
diff --git a/src/cockpit/389-console/src/index.html
b/src/cockpit/389-console/src/index.html
index 5015717..96586d1 100644
--- a/src/cockpit/389-console/src/index.html
+++ b/src/cockpit/389-console/src/index.html
@@ -35,6 +35,7 @@
</head>
<body>
+ <div id="reload-page" hidden></div>
<div id="loading-page" class="ds-center ds-loading-spinner"
hidden>
<h3 id="loading-msg">Loading Directory Server
Configuration...</h3>
<p><span class="spinner spinner-lg
spinner-inline"></span></p>
diff --git a/src/cockpit/389-console/src/lib/database/backups.jsx
b/src/cockpit/389-console/src/lib/database/backups.jsx
index 646fb95..6ddcc44 100644
--- a/src/cockpit/389-console/src/lib/database/backups.jsx
+++ b/src/cockpit/389-console/src/lib/database/backups.jsx
@@ -86,6 +86,7 @@ export class Backups extends React.Component {
this.setState({
showExportModal: true,
exportSpinner: false,
+ ldifName: "",
ldifSuffix: this.props.suffixes[0]
});
}
@@ -147,7 +148,8 @@ export class Backups extends React.Component {
showBackupModal () {
this.setState({
showBackupModal: true,
- backupSpinning: false
+ backupSpinning: false,
+ backupName: ""
});
}
@@ -289,10 +291,15 @@ export class Backups extends React.Component {
backupSpinning: true
});
- const cmd = [
+ let cmd = [
"dsconf", "-j", "ldapi://%2fvar%2frun%2fslapd-"
+ this.props.serverId + ".socket",
- "backup", "create", this.state.backupName
+ "backup", "create"
];
+
+ if (this.state.backupName != "") {
+ cmd.push(this.state.backupName);
+ }
+
log_cmd("doBackup", "Add backup task", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
@@ -615,7 +622,7 @@ class ExportModal extends React.Component {
</Col>
</Row>
<p />
- <Row title="Name of exported LDIF file">
+ <Row title="Name of exported LDIF file, if left blank
the data and time will be used as the file name">
<Col sm={3}>
<ControlLabel>LDIF File
Name</ControlLabel>
</Col>
@@ -691,7 +698,7 @@ export class BackupModal extends React.Component {
</Modal.Header>
<Modal.Body>
<Form horizontal autoComplete="off">
- <Row title="LDIF file to import">
+ <Row title="Backup name, if left blank the date and
time will be used as the name">
<Col sm={3}>
<ControlLabel>Backup Name</ControlLabel>
</Col>
diff --git a/src/cockpit/389-console/src/plugins.jsx
b/src/cockpit/389-console/src/plugins.jsx
index 5481d1a..e14b92d 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -182,7 +182,7 @@ export class Plugins extends React.Component {
})
.fail(err => {
if (err != 0) {
- console.error("pluginList failed", err);
+ console.log("pluginList failed", err);
}
this.toggleLoading();
});
diff --git a/src/cockpit/389-console/src/servers.js
b/src/cockpit/389-console/src/servers.js
index 4d1865c..f23b785 100644
--- a/src/cockpit/389-console/src/servers.js
+++ b/src/cockpit/389-console/src/servers.js
@@ -413,19 +413,35 @@ function do_backup(server_inst, backup_name) {
var cmd = ['status-dirsrv', server_inst];
$("#backup-spinner").show();
cockpit.spawn(cmd, { superuser: true}).
- done(function() {
- var cmd = [DSCONF, server_inst, 'backup', 'create', backup_name];
- log_cmd('#ds-backup-btn (click)', 'Backup server instance', cmd);
- cockpit.spawn(cmd, { superuser: true, "err": "message",
"environ": [ENV]}).
- done(function(data) {
- $("#backup-spinner").hide();
- popup_success("Backup has been created");
- $("#backup-form").modal('toggle');
- }).
- fail(function(data) {
- $("#backup-spinner").hide();
- popup_err("Failed to backup the server", data.message);
- })
+ done(function(status_data) {
+ var status_json = JSON.parse(status_data);
+ if (status_json.running == true) {
+ var cmd = [DSCONF, "-j", server_inst, 'backup', 'create',
backup_name];
+ log_cmd('#ds-backup-btn (click)', 'Backup server instance', cmd);
+ cockpit.spawn(cmd, { superuser: true, "err": "message",
"environ": [ENV]}).
+ done(function(data) {
+ $("#backup-spinner").hide();
+ popup_success("Backup has been created");
+ $("#backup-form").modal('toggle');
+ }).
+ fail(function(data) {
+ $("#backup-spinner").hide();
+ popup_err("Failed to backup the server", data.message);
+ })
+ } else {
+ var cmd = [DSCTL, server_inst, 'db2bak', backup_name];
+ log_cmd('#ds-backup-btn (click)', 'Backup server instance
(offline)', cmd);
+ cockpit.spawn(cmd, { superuser: true, "err": "message",
"environ": [ENV]}).
+ done(function(data) {
+ $("#backup-spinner").hide();
+ popup_success("Backup has been created");
+ $("#backup-form").modal('toggle');
+ }).
+ fail(function(data) {
+ $("#backup-spinner").hide();
+ popup_err("Failed to backup the server", data.message);
+ });
+ }
}).
fail(function() {
var cmd = [DSCTL, server_inst, 'db2bak', backup_name];
@@ -466,7 +482,7 @@ $(document).ready( function() {
log_cmd('#start-server-btn (click)', 'Start server instance',
cmd);
cockpit.spawn(cmd, { superuser: true, "err": "message",
"environ": [ENV]}).done(function(data) {
$("#start-instance-form").modal('toggle');
- load_config();
+ load_config(true);
popup_success("Started instance \"" + server_id +
"\"");
}).fail(function(data) {
$("#start-instance-form").modal('toggle');
@@ -492,13 +508,13 @@ $(document).ready( function() {
document.getElementById("restart-server-btn").addEventListener("click",
function() {
- $("#ds-restart-inst").html("<span class=\"spinner
spinner-xs spinner-inline\"></span> Retarting instance <b>" +
server_id + "</b>...");
+ $("#ds-restart-inst").html("<span class=\"spinner
spinner-xs spinner-inline\"></span> Restarting instance <b>" +
server_id + "</b>...");
$("#restart-instance-form").modal('toggle');
var cmd = [DSCTL, server_inst, 'restart'];
log_cmd('#restart-server-btn (click)', 'Restart server
instance', cmd);
cockpit.spawn(cmd, { superuser: true, "err": "message",
"environ": [ENV]}).done(function(data) {
$("#restart-instance-form").modal('toggle');
- load_config();
+ load_config(true);
popup_success("Restarted instance \"" + server_id +
"\"");
}).fail(function(data) {
$("#restart-instance-form").modal('toggle');
diff --git a/src/lib389/lib389/backend.py b/src/lib389/lib389/backend.py
index 7535c06..64a40c1 100644
--- a/src/lib389/lib389/backend.py
+++ b/src/lib389/lib389/backend.py
@@ -480,8 +480,20 @@ class Backend(DSLdapObject):
:returns: DSLdapObject of the created entry
"""
+ # normalize suffix (remove spaces between comps)
+ if dn is not None:
+ dn_comps = ldap.dn.explode_dn(dn.lower())
+ dn = ",".join(dn_comps)
+
+ if properties is not None:
+ suffix_dn = properties['nsslapd-suffix'].lower()
+ dn_comps = ldap.dn.explode_dn(suffix_dn)
+ ndn = ",".join(dn_comps)
+ properties['nsslapd-suffix'] = ndn
+
sample_entries = properties.pop(BACKEND_SAMPLE_ENTRIES, False)
parent_suffix = properties.pop('parent', False)
+
# Okay, now try to make the backend.
super(Backend, self).create(dn, properties, basedn)
@@ -798,6 +810,8 @@ class Backends(DSLdapObjects):
task = ExportTask(self._instance)
task_properties = {'nsInstance': be_names}
+ if ldif == "":
+ ldif = None
if ldif is not None and not ldif.startswith("/"):
if ldif.endswith(".ldif"):
task_properties['nsFilename'] =
os.path.join(self._instance.ds_paths.ldif_dir, ldif)
diff --git a/src/lib389/lib389/cli_conf/backend.py
b/src/lib389/lib389/cli_conf/backend.py
index dbc8aa6..18da186 100644
--- a/src/lib389/lib389/cli_conf/backend.py
+++ b/src/lib389/lib389/cli_conf/backend.py
@@ -376,9 +376,14 @@ 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')
- mt = be._mts.get(suffix)
+ 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
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))
diff --git a/src/lib389/lib389/pwpolicy.py b/src/lib389/lib389/pwpolicy.py
index d665d1f..2221958 100644
--- a/src/lib389/lib389/pwpolicy.py
+++ b/src/lib389/lib389/pwpolicy.py
@@ -27,48 +27,48 @@ class PwPolicyManager(object):
def __init__(self, instance):
self._instance = instance
self.log = instance.log
- self.pwp_attributes = [
- 'passwordstoragescheme',
- 'passwordChange',
- 'passwordMustChange',
- 'passwordHistory',
- 'passwordInHistory',
- 'passwordAdminDN',
- 'passwordTrackUpdateTime',
- 'passwordWarning',
- 'passwordMaxAge',
- 'passwordMinAge',
- 'passwordExp',
- 'passwordGraceLimit',
- 'passwordSendExpiringTime',
- 'passwordLockout',
- 'passwordUnlock',
- 'passwordMaxFailure',
- 'passwordLockoutDuration',
- 'passwordResetFailureCount',
- 'passwordCheckSyntax',
- 'passwordMinLength',
- 'passwordMinDigits',
- 'passwordMinAlphas',
- 'passwordMinUppers',
- 'passwordMinLowers',
- 'passwordMinSpecials',
- 'passwordMaxRepeats',
- 'passwordMin8bit',
- 'passwordMinCategories',
- 'passwordMinTokenLength',
- 'passwordDictPath',
- 'passwordDictCheck',
- 'passwordPalindrome',
- 'passwordMaxSequence',
- 'passwordMaxClassChars',
- 'passwordMaxSeqSets',
- 'passwordBadWords',
- 'passwordUserAttributes',
- 'passwordIsGlobalPolicy',
- 'nsslapd-pwpolicy-local',
- 'nsslapd-allow-hashed-passwords'
- ]
+ self.arg_to_attr = {
+ 'pwdlocal': 'nsslapd-pwpolicy-local',
+ 'pwdscheme': 'passwordstoragescheme',
+ 'pwdchange': 'passwordChange',
+ 'pwdmustchange': 'passwordMustChange',
+ 'pwdhistory': 'passwordHistory',
+ 'pwdhistorycount': 'passwordInHistory',
+ 'pwdadmin': 'passwordAdminDN',
+ 'pwdtrack': 'passwordTrackUpdateTime',
+ 'pwdwarning': 'passwordWarning',
+ 'pwdisglobal': 'passwordIsGlobalPolicy',
+ 'pwdexpire': 'passwordExp',
+ 'pwdmaxage': 'passwordMaxAge',
+ 'pwdminage': 'passwordMinAge',
+ 'pwdgracelimit': 'passwordGraceLimit',
+ 'pwdsendexpiring': 'passwordSendExpiringTime',
+ 'pwdlockout': 'passwordLockout',
+ 'pwdunlock': 'passwordUnlock',
+ 'pwdlockoutduration': 'passwordLockoutDuration',
+ 'pwdmaxfailures': 'passwordMaxFailure',
+ 'pwdresetfailcount': 'passwordResetFailureCount',
+ 'pwdchecksyntax': 'passwordCheckSyntax',
+ 'pwdminlen': 'passwordMinLength',
+ 'pwdmindigits': 'passwordMinDigits',
+ 'pwdminalphas': 'passwordMinAlphas',
+ 'pwdminuppers': 'passwordMinUppers',
+ 'pwdminlowers': 'passwordMinLowers',
+ 'pwdminspecials': 'passwordMinSpecials',
+ 'pwdmin8bits': 'passwordMin8bit',
+ 'pwdmaxrepeats': 'passwordMaxRepeats',
+ 'pwdpalindrome': 'passwordPalindrome',
+ 'pwdmaxseq': 'passwordMaxSequence',
+ 'pwdmaxseqsets': 'passwordMaxSeqSets',
+ 'pwdmaxclasschars': 'passwordMaxClassChars',
+ 'pwdmincatagories': 'passwordMinCategories',
+ 'pwdmintokenlen': 'passwordMinTokenLength',
+ 'pwdbadwords': 'passwordBadWords',
+ 'pwduserattrs': 'passwordUserAttributes',
+ 'pwddictcheck': 'passwordDictCheck',
+ 'pwddictpath': 'passwordDictPath',
+ 'pwdallowhash': 'nsslapd-allow-hashed-passwords'
+ }
def is_user_policy(self, dn):
"""Check if the entry has a user password policy
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.