From 0a3438939ad56cedefd105b37a279a74c2504c06 Mon Sep 17 00:00:00 2001 From: Simon Pichugin Date: Sep 02 2019 16:16:10 +0000 Subject: Issue 50545 - Port fixup-memberuid and add the functionality to CLI and UI Description: fixup-memberuid.pl script corrects mismatched member and uniquemember values. Port to existing CLI tools and add the button (similar to memberOf fixup task) to UI. https://pagure.io/389-ds-base/issue/50545 Reviewed by: mreynolds, firstyear (Thanks!) --- diff --git a/src/cockpit/389-console/src/lib/plugins/winsync.jsx b/src/cockpit/389-console/src/lib/plugins/winsync.jsx index ed5b657..0e2ff13 100644 --- a/src/cockpit/389-console/src/lib/plugins/winsync.jsx +++ b/src/cockpit/389-console/src/lib/plugins/winsync.jsx @@ -1,7 +1,21 @@ +import cockpit from "cockpit"; import React from "react"; -import { Row, Col, Form, noop, FormGroup, Checkbox, ControlLabel } from "patternfly-react"; +import { + Row, + Col, + Icon, + Modal, + noop, + Form, + FormControl, + FormGroup, + Checkbox, + Button, + ControlLabel +} from "patternfly-react"; import PropTypes from "prop-types"; import PluginBasicConfig from "./pluginBasicConfig.jsx"; +import { log_cmd } from "../tools.jsx"; import "../../css/ds.css"; class WinSync extends React.Component { @@ -19,23 +33,93 @@ class WinSync extends React.Component { super(props); this.handleCheckboxChange = this.handleCheckboxChange.bind(this); + this.handleFieldChange = this.handleFieldChange.bind(this); this.updateFields = this.updateFields.bind(this); + this.runFixup = this.runFixup.bind(this); + this.toggleFixupModal = this.toggleFixupModal.bind(this); this.state = { posixWinsyncCreateMemberOfTask: false, posixWinsyncLowerCaseUID: false, posixWinsyncMapMemberUID: false, posixWinsyncMapNestedGrouping: false, - posixWinsyncMsSFUSchema: false + posixWinsyncMsSFUSchema: false, + + fixupModalShow: false, + fixupDN: "", + fixupFilter: "" }; } + toggleFixupModal() { + this.setState(prevState => ({ + fixupModalShow: !prevState.fixupModalShow, + fixupDN: "", + fixupFilter: "" + })); + } + + runFixup() { + if (!this.state.fixupDN) { + this.props.addNotification("warning", "Fixup DN is required."); + } else { + let cmd = [ + "dsconf", + "-j", + "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId + ".socket", + "plugin", + "posix-winsync", + "fixup", + this.state.fixupDN + ]; + + if (this.state.fixupFilter) { + cmd = [...cmd, "--filter", this.state.fixupFilter]; + } + + this.props.toggleLoadingHandler(); + log_cmd("runFixup", "Run Member UID task", cmd); + cockpit + .spawn(cmd, { + superuser: true, + err: "message" + }) + .done(content => { + this.props.addNotification( + "success", + `Fixup task for ${this.state.fixupDN} was successfull` + ); + this.props.toggleLoadingHandler(); + this.setState({ + fixupModalShow: false + }); + }) + .fail(err => { + let errMsg = JSON.parse(err); + this.props.addNotification( + "error", + `Fixup task for ${this.state.fixupDN} has failed ${errMsg.desc}` + ); + this.props.toggleLoadingHandler(); + this.setState({ + fixupModalShow: false + }); + }); + } + } + handleCheckboxChange(e) { this.setState({ [e.target.id]: e.target.checked }); } + handleFieldChange(e) { + this.setState({ + [e.target.id]: e.target.value + }); + } + updateFields() { if (this.props.rows.length > 0) { const pluginRow = this.props.rows.find(row => row.cn[0] === "Posix Winsync API"); @@ -71,7 +155,10 @@ class WinSync extends React.Component { posixWinsyncLowerCaseUID, posixWinsyncMapMemberUID, posixWinsyncMapNestedGrouping, - posixWinsyncMsSFUSchema + posixWinsyncMsSFUSchema, + fixupModalShow, + fixupDN, + fixupFilter } = this.state; let specificPluginCMD = [ @@ -94,6 +181,69 @@ class WinSync extends React.Component { ]; return (
+ +
+ + + MemberOf Task + + + + +
+ + + + Base DN + + + + + + + + + + Filter DN + + + + + + +
+ +
+
+ + + + +
+
Create MemberOf Task @@ -134,7 +284,7 @@ class WinSync extends React.Component { > Lower Case UID @@ -153,7 +303,7 @@ class WinSync extends React.Component { > Map Member UID @@ -173,7 +323,7 @@ class WinSync extends React.Component { Map Nested Grouping @@ -191,7 +341,7 @@ class WinSync extends React.Component { > Microsoft System Services for Unix 3.0 (msSFU30) schema @@ -207,6 +357,17 @@ class WinSync extends React.Component { + + + + +
); diff --git a/src/lib389/lib389/cli_conf/plugins/posix_winsync.py b/src/lib389/lib389/cli_conf/plugins/posix_winsync.py index e2856af..0512418 100644 --- a/src/lib389/lib389/cli_conf/plugins/posix_winsync.py +++ b/src/lib389/lib389/cli_conf/plugins/posix_winsync.py @@ -24,6 +24,21 @@ def winsync_edit(inst, basedn, log, args): generic_object_edit(plugin, log, args, arg_to_attr) +def do_fixup(inst, basedn, log, args): + plugin = POSIXWinsyncPlugin(inst) + log.info('Attempting to add task entry...') + if not plugin.status(): + log.error(f"'{plugin.rdn}' is disabled. Fix up task can't be executed") + return + fixup_task = plugin.fixup(args.DN, args.filter) + fixup_task.wait() + exitcode = fixup_task.get_exit_code() + if exitcode != 0: + log.error(f'MemberUID task for {args.DN} has failed. Please, check logs') + else: + log.info('Successfully added task entry') + + def _add_parser_args(parser): parser.add_argument('--create-memberof-task', choices=['true', 'false'], type=str.lower, help='Sets whether to run the memberOf fix-up task immediately after a sync run in order ' @@ -51,3 +66,10 @@ def create_parser(subparsers): edit.set_defaults(func=winsync_edit) _add_parser_args(edit) + fixup = subcommands.add_parser('fixup', help='Run the memberOf fix-up task to correct mismatched member and uniquemember values for synced users') + fixup.set_defaults(func=do_fixup) + fixup.add_argument('DN', help="Base DN that contains entries to fix up") + fixup.add_argument('-f', '--filter', + help='Filter for entries to fix up.\n If omitted, all entries with objectclass ' + 'inetuser/inetadmin/nsmemberof under the specified base will have ' + 'their memberOf attribute regenerated.') diff --git a/src/lib389/lib389/plugins.py b/src/lib389/lib389/plugins.py index a8b13c7..a8b8985 100644 --- a/src/lib389/lib389/plugins.py +++ b/src/lib389/lib389/plugins.py @@ -1340,6 +1340,25 @@ class POSIXWinsyncPlugin(Plugin): def __init__(self, instance, dn="cn=Posix Winsync API,cn=plugins,cn=config"): super(POSIXWinsyncPlugin, self).__init__(instance, dn) + def fixup(self, basedn, _filter=None): + """Create a memberuid task + + :param basedn: Basedn to fix up + :type basedn: str + :param _filter: a filter for entries to fix up + :type _filter: str + + :returns: an instance of Task(DSLdapObject) + """ + + task = tasks.MemberUidFixupTask(self._instance) + task_properties = {'basedn': basedn} + if _filter is not None: + task_properties['filter'] = _filter + task.create(properties=task_properties) + + return task + class PAMPassThroughAuthPlugin(Plugin): """A single instance of PAM Pass Through Auth plugin entry diff --git a/src/lib389/lib389/tasks.py b/src/lib389/lib389/tasks.py index f12943f..af97634 100644 --- a/src/lib389/lib389/tasks.py +++ b/src/lib389/lib389/tasks.py @@ -139,6 +139,21 @@ class FixupLinkedAttributesTask(Task): super(FixupLinkedAttributesTask, self).__init__(instance, dn) +class MemberUidFixupTask(Task): + """A single instance of memberOf task entry + + :param instance: An instance + :type instance: lib389.DirSrv + """ + + def __init__(self, instance, dn=None): + self.cn = 'memberUid_fixup_' + Task._get_task_date() + dn = f"cn={self.cn},cn=memberuid task,cn=tasks,cn=config" + + super(MemberUidFixupTask, self).__init__(instance, dn) + self._must_attributes.extend(['basedn']) + + class MemberOfFixupTask(Task): """A single instance of memberOf task entry