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 0be0149 Issue 50041 - CLI and WebUI - Add memberOf plugin functionality
0be0149 is described below
commit 0be01490e171aa1aacba57616940f22b20481e7d
Author: Simon Pichugin <spichugi(a)redhat.com>
AuthorDate: Wed Jan 9 21:07:55 2019 +0100
Issue 50041 - CLI and WebUI - Add memberOf plugin functionality
Description: Add the main functionality to memberOf plugin tab.
Increase the eslint max line length from 80 to 100.
Rework plugin properties to be more compact.
Eslint webpack config. Add react-bootstrap-typeahead for
multivalued attributes. Fix the word 'successfully' typos.
https://pagure.io/389-ds-base/issue/50041
Reviewed by: mreynolds, wibrown (Thanks!)
---
src/cockpit/389-console/.eslintrc.json | 3 +-
src/cockpit/389-console/package.json | 7 +-
src/cockpit/389-console/src/css/ds.css | 16 +-
src/cockpit/389-console/src/index.html | 1 +
src/cockpit/389-console/src/lib/customCollapse.jsx | 1 -
.../389-console/src/lib/plugins/memberOf.jsx | 955 ++++++++++++++++++++-
.../src/lib/plugins/pluginBasicConfig.jsx | 227 ++---
.../389-console/src/lib/plugins/pluginModal.jsx | 165 ++--
src/cockpit/389-console/src/plugins.jsx | 153 +++-
src/cockpit/389-console/src/static/Typeahead.css | 256 ++++++
src/cockpit/389-console/webpack.config.js | 72 +-
src/lib389/lib389/_mapped_object.py | 31 +-
src/lib389/lib389/cli_conf/__init__.py | 73 +-
src/lib389/lib389/cli_conf/backend.py | 6 +-
src/lib389/lib389/cli_conf/plugin.py | 44 +-
src/lib389/lib389/cli_conf/plugins/memberof.py | 356 +++-----
src/lib389/lib389/cli_ctl/instance.py | 5 +-
src/lib389/lib389/cli_idm/__init__.py | 4 +-
src/lib389/lib389/clitools/ds_setup | 3 +-
src/lib389/lib389/replica.py | 20 +-
src/lib389/lib389/tests/cli/conf_backend_test.py | 12 +-
src/lib389/lib389/tests/cli/conf_chaining_test.py | 4 +-
src/lib389/lib389/tests/cli/idm_group_test.py | 7 +-
src/lib389/lib389/tests/cli/idm_user_test.py | 7 +-
24 files changed, 1837 insertions(+), 591 deletions(-)
diff --git a/src/cockpit/389-console/.eslintrc.json
b/src/cockpit/389-console/.eslintrc.json
index 11a82c8..ee0a235 100644
--- a/src/cockpit/389-console/.eslintrc.json
+++ b/src/cockpit/389-console/.eslintrc.json
@@ -44,7 +44,8 @@
"eqeqeq": "off",
"import/no-webpack-loader-syntax": "off",
"object-property-newline": "off",
- "react/jsx-no-bind": "off"
+ "react/jsx-no-bind": "off",
+ "max-len": ["error", { "code": 100 }]
},
"globals": {
"require": false,
diff --git a/src/cockpit/389-console/package.json b/src/cockpit/389-console/package.json
index 054a373..0699691 100644
--- a/src/cockpit/389-console/package.json
+++ b/src/cockpit/389-console/package.json
@@ -14,13 +14,13 @@
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
+ "ajv": "^6.0.0",
"babel-eslint": "^9.0.0",
"babel-loader": "^8.0.0",
"chrome-remote-interface": "^0.25.5",
"compression-webpack-plugin": "^1.1.11",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^0.28.11",
- "style-loader": "^0.23.1",
"eslint": "^5.4.0",
"eslint-config-standard": "^11.0.0",
"eslint-config-standard-react": "^6.0.0",
@@ -34,17 +34,20 @@
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"htmlparser": "^1.7.7",
"jed": "^1.1.1",
- "ajv": "^6.0.0",
"sass-loader": "^7.0.3",
"sizzle": "^2.3.3",
"stdio": "^0.2.7",
+ "style-loader": "^0.23.1",
"webpack": "^4.17.1",
"webpack-cli": "^3.1.0"
},
"dependencies": {
"patternfly": "3.58.0",
"patternfly-react": "2.24.5",
+ "bootstrap": "4.2.1",
+ "node-sass": "4.11.0",
"react-bootstrap": "0.32.4",
+ "react-bootstrap-typeahead": "3.2.4",
"react": "16.6.1",
"react-dom": "16.6.1",
"prop-types": "15.6.2",
diff --git a/src/cockpit/389-console/src/css/ds.css
b/src/cockpit/389-console/src/css/ds.css
index d38ff55..8e9ba21 100644
--- a/src/cockpit/389-console/src/css/ds.css
+++ b/src/cockpit/389-console/src/css/ds.css
@@ -1310,7 +1310,7 @@ option {
.ds-td {
padding-left: 10px !important;
padding-top: 8px !important;
- padding-bottom: 0px ~important;
+ padding-bottom: 0px !important;
valign: middle !important;
}
@@ -1454,6 +1454,11 @@ tbody:nth-child(even) {
bottom: 10px;
}
+.ds-plugin-button {
+ margin-right: 5px;
+ margin-left: 5px;
+}
+
.ds-plugin-spinner {
margin-top: 20px;
margin-bottom: 10px;
@@ -1494,3 +1499,12 @@ tbody:nth-child(even) {
.control-label {
text-align: left !important;
}
+
+.rbt-token {
+ background-color: #ededed;
+ color: #363636;
+}
+
+.rbt-input-multi {
+ height: auto !important;
+}
diff --git a/src/cockpit/389-console/src/index.html
b/src/cockpit/389-console/src/index.html
index 6b3f213..b23a722 100644
--- a/src/cockpit/389-console/src/index.html
+++ b/src/cockpit/389-console/src/index.html
@@ -30,6 +30,7 @@
<link href="static/jquery.timepicker.min.css" type="text/css"
rel="stylesheet">
<link href="static/style.min.css" rel="stylesheet">
<link href="static/patternfly-additions.css" rel="stylesheet"
type="text/css">
+ <link href="static/Typeahead.css" rel="stylesheet"
type="text/css">
<link rel="stylesheet" href="../base1/patternfly.css">
<link href="css/ds.css" type="text/css"
rel="stylesheet">
</head>
diff --git a/src/cockpit/389-console/src/lib/customCollapse.jsx
b/src/cockpit/389-console/src/lib/customCollapse.jsx
index 71ea0f5..b992982 100644
--- a/src/cockpit/389-console/src/lib/customCollapse.jsx
+++ b/src/cockpit/389-console/src/lib/customCollapse.jsx
@@ -26,7 +26,6 @@ class CustomCollapse extends React.Component {
<Icon
type="fa"
- size="1,5x"
name={open ? "caret-down" : "caret-right"}
/>{" "}
{open ? textOpened : textClosed}
diff --git a/src/cockpit/389-console/src/lib/plugins/memberOf.jsx
b/src/cockpit/389-console/src/lib/plugins/memberOf.jsx
index 33a2091..51ecd59 100644
--- a/src/cockpit/389-console/src/lib/plugins/memberOf.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/memberOf.jsx
@@ -1,24 +1,975 @@
+import cockpit from "cockpit";
import React from "react";
-import { noop } from "patternfly-react";
+import {
+ Icon,
+ Modal,
+ Button,
+ Row,
+ Col,
+ Form,
+ noop,
+ FormGroup,
+ FormControl,
+ Checkbox,
+ ControlLabel
+} from "patternfly-react";
+import { Typeahead } from "react-bootstrap-typeahead";
import PropTypes from "prop-types";
import PluginBasicConfig from "./pluginBasicConfig.jsx";
+import { log_cmd } from "../tools.jsx";
import "../../css/ds.css";
class MemberOf extends React.Component {
+ componentWillMount(prevProps) {
+ this.updateFields();
+ }
+
+ componentDidUpdate(prevProps) {
+ if (this.props.rows !== prevProps.rows) {
+ this.updateFields();
+ }
+ }
+
+ constructor(props) {
+ super(props);
+
+ this.updateFields = this.updateFields.bind(this);
+ this.handleFieldChange = this.handleFieldChange.bind(this);
+ this.handleCheckboxChange = this.handleCheckboxChange.bind(this);
+ this.openModal = this.openModal.bind(this);
+ this.closeModal = this.closeModal.bind(this);
+ this.addConfig = this.addConfig.bind(this);
+ this.editConfig = this.editConfig.bind(this);
+ this.deleteConfig = this.deleteConfig.bind(this);
+ this.cmdOperation = this.cmdOperation.bind(this);
+ this.runFixup = this.runFixup.bind(this);
+ this.toggleFixupModal = this.toggleFixupModal.bind(this);
+
+ this.state = {
+ memberOfAttr: [],
+ memberOfGroupAttr: [],
+ memberOfEntryScope: "",
+ memberOfEntryScopeExcludeSubtree: "",
+ memberOfAutoAddOC: "",
+ memberOfAllBackends: false,
+ memberOfSkipNested: false,
+ memberOfConfigEntry: "",
+ configEntryModalShow: false,
+ fixupModalShow: false,
+
+ configDN: "",
+ configAttr: [],
+ configGroupAttr: [],
+ configEntryScope: "",
+ configEntryScopeExcludeSubtree: "",
+ configAutoAddOC: "",
+ configAllBackends: false,
+ configSkipNested: false,
+ newEntry: true,
+
+ 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",
+ "memberof",
+ "fixup",
+ this.state.fixupDN
+ ];
+
+ if (this.state.fixupFilter) {
+ cmd = [...cmd, "--filter", this.state.fixupFilter];
+ }
+
+ this.props.toggleLoadingHandler();
+ log_cmd("runFixup", "Run fixup MemberOf Plugin ", 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 => {
+ this.props.addNotification(
+ "error",
+ `Fixup task for ${this.state.fixupDN} has failed ${err}`
+ );
+ this.props.toggleLoadingHandler();
+ this.setState({
+ fixupModalShow: false
+ });
+ });
+ }
+ }
+
+ openModal() {
+ if (!this.state.memberOfConfigEntry) {
+ this.setState({
+ configEntryModalShow: true,
+ newEntry: true,
+ configDN: "",
+ configAttr: [],
+ configGroupAttr: [],
+ configEntryScope: "",
+ configEntryScopeExcludeSubtree: "",
+ configAutoAddOC: "",
+ configAllBackends: false,
+ configSkipNested: false
+ });
+ } else {
+ let configAttrObjectList = [];
+ let configGroupAttrObjectList = [];
+ let cmd = [
+ "dsconf",
+ "-j",
+ "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId +
".socket",
+ "plugin",
+ "memberof",
+ "config-entry",
+ "show",
+ this.state.memberOfConfigEntry
+ ];
+
+ this.props.toggleLoadingHandler();
+ log_cmd("openMemberOfModal", "Fetch the MemberOf Plugin config
entry", cmd);
+ cockpit
+ .spawn(cmd, {
+ superuser: true,
+ err: "message"
+ })
+ .done(content => {
+ let configEntry = JSON.parse(content).attrs;
+ this.setState({
+ configEntryModalShow: true,
+ newEntry: false,
+ configDN: this.state.memberOfConfigEntry,
+ configAutoAddOC:
+ configEntry["memberofautoaddoc"] === undefined
+ ? ""
+ : configEntry["memberofautoaddoc"][0],
+ configAllBackends: !(
+ configEntry["memberofallbackends"] ===
undefined ||
+ configEntry["memberofallbackends"][0] ==
"off"
+ ),
+ configSkipNested: !(
+ configEntry["memberofskipnested"] === undefined
||
+ configEntry["memberofskipnested"][0] ==
"off"
+ ),
+ configConfigEntry:
+ configEntry["nsslapd-pluginConfigArea"] ===
undefined
+ ? ""
+ : configEntry["nsslapd-pluginConfigArea"][0],
+ configEntryScope:
+ configEntry["memberofentryscope"] === undefined
+ ? ""
+ : configEntry["memberofentryscope"][0],
+ configEntryScopeExcludeSubtree:
+ configEntry["memberofentryscopeexcludesubtree"] ===
undefined
+ ? ""
+ :
configEntry["memberofentryscopeexcludesubtree"][0]
+ });
+ if (configEntry["memberofattr"] === undefined) {
+ this.setState({ configAttr: [] });
+ } else {
+ for (let value of configEntry["memberofattr"]) {
+ configAttrObjectList = [
+ ...configAttrObjectList,
+ { id: value, label: value }
+ ];
+ }
+ this.setState({ configAttr: configAttrObjectList });
+ }
+ if (configEntry["memberofgroupattr"] === undefined) {
+ this.setState({ configGroupAttr: [] });
+ } else {
+ for (let value of configEntry["memberofgroupattr"])
{
+ configGroupAttrObjectList = [
+ ...configGroupAttrObjectList,
+ { id: value, label: value }
+ ];
+ }
+ this.setState({ configGroupAttr: configGroupAttrObjectList
});
+ this.props.toggleLoadingHandler();
+ }
+ })
+ .fail(_ => {
+ this.setState({
+ configEntryModalShow: true,
+ newEntry: true,
+ configDN: this.state.memberOfConfigEntry,
+ configAttr: [],
+ configGroupAttr: [],
+ configEntryScope: "",
+ configEntryScopeExcludeSubtree: "",
+ configAutoAddOC: "",
+ configAllBackends: false,
+ configSkipNested: false
+ });
+ this.props.toggleLoadingHandler();
+ });
+ }
+ }
+
+ closeModal() {
+ this.setState({ configEntryModalShow: false });
+ }
+
+ cmdOperation(action) {
+ const {
+ configDN,
+ configAttr,
+ configGroupAttr,
+ configEntryScope,
+ configEntryScopeExcludeSubtree,
+ configAutoAddOC,
+ configAllBackends,
+ configSkipNested
+ } = this.state;
+
+ if (configAttr.length == 0 || configGroupAttr.length == 0) {
+ this.props.addNotification(
+ "warning",
+ "Config Attribute and Group Attribute are required."
+ );
+ } else {
+ let cmd = [
+ "dsconf",
+ "-j",
+ "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId +
".socket",
+ "plugin",
+ "memberof",
+ "config-entry",
+ action,
+ configDN,
+ "--scope",
+ configEntryScope || action == "add" ? configEntryScope :
"delete",
+ "--exclude",
+ configEntryScopeExcludeSubtree || action == "add"
+ ? configEntryScopeExcludeSubtree
+ : "delete",
+ "--autoaddoc",
+ configAutoAddOC || action == "add" ? configAutoAddOC :
"delete",
+ "--allbackends",
+ configAllBackends ? "on" : "off",
+ "--skipnested",
+ configSkipNested ? "on" : "off"
+ ];
+
+ // Delete attributes if the user set an empty value to the field
+ cmd = [...cmd, "--attr"];
+ if (configAttr.length != 0) {
+ for (let value of configAttr) {
+ cmd = [...cmd, value.label];
+ }
+ }
+ cmd = [...cmd, "--groupattr"];
+ if (configGroupAttr.length != 0) {
+ for (let value of configGroupAttr) {
+ cmd = [...cmd, value.label];
+ }
+ }
+
+ this.props.toggleLoadingHandler();
+ log_cmd("memberOfOperation", `Do the ${action} operation on the
MemberOf Plugin`, cmd);
+ cockpit
+ .spawn(cmd, {
+ superuser: true,
+ err: "message"
+ })
+ .done(content => {
+ console.info("memberOfOperation", "Result",
content);
+ this.props.addNotification(
+ "success",
+ `Config entry ${configDN} was successfully ${action}ed`
+ );
+ this.props.pluginListHandler();
+ this.closeModal();
+ this.props.toggleLoadingHandler();
+ })
+ .fail(err => {
+ this.props.addNotification(
+ "error",
+ `Error during the config entry ${action} operation - ${err}`
+ );
+ this.props.pluginListHandler();
+ this.closeModal();
+ this.props.toggleLoadingHandler();
+ });
+ }
+ }
+
+ deleteConfig() {
+ let cmd = [
+ "dsconf",
+ "-j",
+ "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId +
".socket",
+ "plugin",
+ "memberof",
+ "config-entry",
+ "delete",
+ this.state.configDN
+ ];
+
+ this.props.toggleLoadingHandler();
+ log_cmd("deleteConfig", "Delete the MemberOf Plugin config
entry", cmd);
+ cockpit
+ .spawn(cmd, {
+ superuser: true,
+ err: "message"
+ })
+ .done(content => {
+ console.info("deleteConfig", "Result", content);
+ this.props.addNotification(
+ "success",
+ `Config entry ${this.state.configDN} was successfully deleted`
+ );
+ this.props.pluginListHandler();
+ this.closeModal();
+ this.props.toggleLoadingHandler();
+ })
+ .fail(err => {
+ this.props.addNotification(
+ "error",
+ `Error during the config entry removal operation - ${err}`
+ );
+ this.props.pluginListHandler();
+ this.closeModal();
+ this.props.toggleLoadingHandler();
+ });
+ }
+
+ addConfig() {
+ this.cmdOperation("add");
+ }
+
+ editConfig() {
+ this.cmdOperation("edit");
+ }
+
+ handleCheckboxChange(e) {
+ this.setState({
+ [e.target.id]: e.target.checked
+ });
+ }
+
+ handleFieldChange(e) {
+ this.setState({
+ [e.target.id]: e.target.value
+ });
+ }
+
+ updateFields() {
+ let memberOfAttrObjectList = [];
+ let memberOfGroupAttrObjectList = [];
+
+ if (this.props.rows.length > 0) {
+ const pluginRow = this.props.rows.find(row => row.cn[0] === "MemberOf
Plugin");
+
+ this.setState({
+ memberOfAutoAddOC:
+ pluginRow["memberofautoaddoc"] === undefined
+ ? ""
+ : pluginRow["memberofautoaddoc"][0],
+ memberOfAllBackends: !(
+ pluginRow["memberofallbackends"] === undefined ||
+ pluginRow["memberofallbackends"][0] == "off"
+ ),
+ memberOfSkipNested: !(
+ pluginRow["memberofskipnested"] === undefined ||
+ pluginRow["memberofskipnested"][0] == "off"
+ ),
+ memberOfConfigEntry:
+ pluginRow["nsslapd-pluginConfigArea"] === undefined
+ ? ""
+ : pluginRow["nsslapd-pluginConfigArea"][0],
+ memberOfEntryScope:
+ pluginRow["memberofentryscope"] === undefined
+ ? ""
+ : pluginRow["memberofentryscope"][0],
+ memberOfEntryScopeExcludeSubtree:
+ pluginRow["memberofentryscopeexcludesubtree"] ===
undefined
+ ? ""
+ : pluginRow["memberofentryscopeexcludesubtree"][0]
+ });
+ if (pluginRow["memberofattr"] === undefined) {
+ this.setState({ memberOfAttr: [] });
+ } else {
+ for (let value of pluginRow["memberofattr"]) {
+ memberOfAttrObjectList = [
+ ...memberOfAttrObjectList,
+ { id: value, label: value }
+ ];
+ }
+ this.setState({ memberOfAttr: memberOfAttrObjectList });
+ }
+ if (pluginRow["memberofgroupattr"] === undefined) {
+ this.setState({ memberOfGroupAttr: [] });
+ } else {
+ for (let value of pluginRow["memberofgroupattr"]) {
+ memberOfGroupAttrObjectList = [
+ ...memberOfGroupAttrObjectList,
+ { id: value, label: value }
+ ];
+ }
+ this.setState({ memberOfGroupAttr: memberOfGroupAttrObjectList });
+ }
+ }
+ }
+
render() {
+ const {
+ memberOfAttr,
+ memberOfGroupAttr,
+ memberOfEntryScope,
+ memberOfEntryScopeExcludeSubtree,
+ memberOfAutoAddOC,
+ memberOfAllBackends,
+ memberOfSkipNested,
+ memberOfConfigEntry,
+ configDN,
+ configEntryModalShow,
+ configAttr,
+ configGroupAttr,
+ configEntryScope,
+ configEntryScopeExcludeSubtree,
+ configAutoAddOC,
+ configAllBackends,
+ configSkipNested,
+ newEntry,
+ fixupModalShow,
+ fixupDN,
+ fixupFilter
+ } = this.state;
+
+ let specificPluginCMD = [
+ "dsconf",
+ "-j",
+ "ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId +
".socket",
+ "plugin",
+ "memberof",
+ "edit",
+ "--scope",
+ memberOfEntryScope || "delete",
+ "--exclude",
+ memberOfEntryScopeExcludeSubtree || "delete",
+ "--autoaddoc",
+ memberOfAutoAddOC || "delete",
+ "--config-entry",
+ memberOfConfigEntry || "delete",
+ "--allbackends",
+ memberOfAllBackends ? "on" : "off",
+ "--skipnested",
+ memberOfSkipNested ? "on" : "off"
+ ];
+
+ // Delete attributes if the user set an empty value to the field
+ specificPluginCMD = [...specificPluginCMD, "--attr"];
+ if (memberOfAttr.length != 0) {
+ for (let value of memberOfAttr) {
+ specificPluginCMD = [...specificPluginCMD, value.label];
+ }
+ } else {
+ specificPluginCMD = [...specificPluginCMD, "delete"];
+ }
+
+ specificPluginCMD = [...specificPluginCMD, "--groupattr"];
+ if (memberOfGroupAttr.length != 0) {
+ for (let value of memberOfGroupAttr) {
+ specificPluginCMD = [...specificPluginCMD, value.label];
+ }
+ } else {
+ specificPluginCMD = [...specificPluginCMD, "delete"];
+ }
+
return (
<div>
+ <Modal show={fixupModalShow} onHide={this.toggleFixupModal}>
+ <div className="ds-no-horizontal-scrollbar">
+ <Modal.Header>
+ <button
+ className="close"
+ onClick={this.toggleFixupModal}
+ aria-hidden="true"
+ aria-label="Close"
+
+
<Icon type="pf" name="close" />
+ </button>
+ <Modal.Title>Fixup MemberOf Task</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Row>
+ <Col sm={12}>
+ <Form horizontal>
+ <FormGroup controlId="fixupDN"
key="fixupDN">
+ <Col sm={3}>
+ <ControlLabel>Base
DN</ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <FormControl
+ type="text"
+ value={fixupDN}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup controlId="fixupFilter"
key="fixupFilter">
+ <Col sm={3}>
+ <ControlLabel>Filter
DN</ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <FormControl
+ type="text"
+ value={fixupFilter}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="default"
+ className="btn-cancel"
+ onClick={this.toggleFixupModal}
+
+
Cancel
+ </Button>
+ <Button bsStyle="primary"
onClick={this.runFixup}>
+ Run
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
+ <Modal show={configEntryModalShow} onHide={this.closeModal}>
+ <div className="ds-no-horizontal-scrollbar">
+ <Modal.Header>
+ <button
+ className="close"
+ onClick={this.closeModal}
+ aria-hidden="true"
+ aria-label="Close"
+
+
<Icon type="pf" name="close" />
+ </button>
+ <Modal.Title>Manage MemberOf Plugin Shared Config
Entry</Modal.Title>
+ </Modal.Header>
+ <Modal.Body>
+ <Row>
+ <Col sm={12}>
+ <Form horizontal>
+ <FormGroup controlId="configDN">
+ <Col sm={3}>
+ <ControlLabel>Config
DN</ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <FormControl
+ type="text"
+ value={configDN}
+ onChange={this.handleFieldChange}
+ disabled={!newEntry}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="configAttr"
+ controlId="configAttr"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Attribute
+ </Col>
+ <Col sm={9}>
+ <Typeahead
+ allowNew
+ multiple
+ onChange={values => {
+ this.setState({
+ configAttr: values
+ });
+ }}
+ selected={configAttr}
+ newSelectionPrefix="Add a
member: "
+ options={[
+ {
+ id: "memberOf",
+ label: "memberOf"
+ }
+ ]}
+ placeholder="Type a member
attribute..."
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="configGroupAttr"
+ controlId="configGroupAttr"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Group Attribute
+ </Col>
+ <Col sm={9}>
+ <Typeahead
+ allowNew
+ multiple
+ onChange={values => {
+ this.setState({
+ configGroupAttr: values
+ });
+ }}
+ selected={configGroupAttr}
+ newSelectionPrefix="Add a group
member: "
+ options={[
+ {
+ id: "member",
+ label: "member"
+ }
+ ]}
+ placeholder="Type a member group
attribute..."
+ />
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ <Row>
+ <Col sm={12}>
+ <Form horizontal>
+ <FormGroup
+ key="configEntryScope"
+ controlId="configEntryScope"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Entry Scope
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+ value={configEntryScope}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ <Col sm={3}>
+ <Checkbox
+ id="configAllBackends"
+ checked={configAllBackends}
+ onChange={this.handleCheckboxChange}
+
+
All Backends
+ </Checkbox>
+ </Col>
+ </FormGroup>
+ <FormGroup
+
key="configEntryScopeExcludeSubtree"
+
controlId="configEntryScopeExcludeSubtree"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Entry Scope Exclude Subtree
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+
value={configEntryScopeExcludeSubtree}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ <Col sm={3}>
+ <Checkbox
+ id="configSkipNested"
+ checked={configSkipNested}
+ onChange={this.handleCheckboxChange}
+
+
Skip Nested
+ </Checkbox>
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ <Row>
+ <Col sm={12}>
+ <Form horizontal>
+ <FormGroup
controlId="configAutoAddOC" disabled={false}>
+ <Col sm={3}>
+ <ControlLabel>Auto Add
OC</ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <FormControl
+ type="text"
+ value={configAutoAddOC}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ </Modal.Body>
+ <Modal.Footer>
+ <Button
+ bsStyle="default"
+ className="btn-cancel"
+ onClick={this.closeModal}
+
+
Cancel
+ </Button>
+ <Button
+ bsStyle="primary"
+ onClick={this.deleteConfig}
+ disabled={newEntry}
+
+
Delete
+ </Button>
+ <Button bsStyle="primary"
onClick={this.editConfig} disabled={newEntry}>
+ Save
+ </Button>
+ <Button bsStyle="primary"
onClick={this.addConfig} disabled={!newEntry}>
+ Add
+ </Button>
+ </Modal.Footer>
+ </div>
+ </Modal>
<PluginBasicConfig
rows={this.props.rows}
serverId={this.props.serverId}
cn="MemberOf Plugin"
pluginName="MemberOf"
cmdName="memberof"
+ specificPluginCMD={specificPluginCMD}
savePluginHandler={this.props.savePluginHandler}
pluginListHandler={this.props.pluginListHandler}
addNotification={this.props.addNotification}
toggleLoadingHandler={this.props.toggleLoadingHandler}
- />
+ >
+ <Row>
+ <Col sm={9}>
+ <Form horizontal>
+ <FormGroup
+ key="memberOfAttr"
+ controlId="memberOfAttr"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Attribute
+ </Col>
+ <Col sm={9}>
+ <Typeahead
+ allowNew
+ multiple
+ onChange={values => {
+ this.setState({
+ memberOfAttr: values
+ });
+ }}
+ selected={memberOfAttr}
+ newSelectionPrefix="Add a member:
"
+ options={[
+ {
+ id: "member",
+ label: "member"
+ },
+ {
+ id: "memberCertificate",
+ label: "memberCertificate"
+ },
+ {
+ id: "uniqueMember",
+ label: "uniqueMember"
+ }
+ ]}
+ placeholder="Type a member
attribute..."
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="memberOfGroupAttr"
+ controlId="memberOfGroupAttr"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Group Attribute
+ </Col>
+ <Col sm={9}>
+ <Typeahead
+ allowNew
+ multiple
+ onChange={values => {
+ this.setState({
+ memberOfGroupAttr: values
+ });
+ }}
+ selected={memberOfGroupAttr}
+ newSelectionPrefix="Add a group member:
"
+ options={[
+ {
+ id: "groupOfNames",
+ label: "groupOfNames"
+ },
+ {
+ id: "groupOfURLs",
+ label: "groupOfURLs"
+ },
+ {
+ id: "groupOfUniqueNames",
+ label:
"groupOfUniqueNames"
+ },
+ {
+ id: "groupOfCertificates",
+ label:
"groupOfCertificates"
+ }
+ ]}
+ placeholder="Type a member group
attribute..."
+ />
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ <Row>
+ <Col sm={9}>
+ <Form horizontal>
+ <FormGroup
+ key="memberOfEntryScope"
+ controlId="memberOfEntryScope"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Entry Scope
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+ value={memberOfEntryScope}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ <Col sm={3}>
+ <Checkbox
+ id="memberOfAllBackends"
+ checked={memberOfAllBackends}
+ onChange={this.handleCheckboxChange}
+
+
All Backends
+ </Checkbox>
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="memberOfEntryScopeExcludeSubtree"
+
controlId="memberOfEntryScopeExcludeSubtree"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Entry Scope Exclude Subtree
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+ value={memberOfEntryScopeExcludeSubtree}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ <Col sm={3}>
+ <Checkbox
+ id="memberOfSkipNested"
+ checked={memberOfSkipNested}
+ onChange={this.handleCheckboxChange}
+
+
Skip Nested
+ </Checkbox>
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ <Row>
+ <Col sm={9}>
+ <Form horizontal>
+ <FormGroup
+ key="memberOfConfigEntry"
+ controlId="memberOfConfigEntry"
+
+
<Col componentClass={ControlLabel} sm={3}>
+ Shared Config Entry
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+ value={memberOfConfigEntry}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ <Col sm={3}>
+ <Button
+ bsSize="large"
+ bsStyle="primary"
+ onClick={this.openModal}
+
+
Manage
+ </Button>
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ <Row>
+ <Col sm={9}>
+ <Form horizontal>
+ <FormGroup controlId="memberOfAutoAddOC"
disabled={false}>
+ <Col sm={3}>
+ <ControlLabel>Auto Add
OC</ControlLabel>
+ </Col>
+ <Col sm={9}>
+ <FormControl
+ type="text"
+ value={memberOfAutoAddOC}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ </Form>
+ </Col>
+ </Row>
+ <Row>
+ <Col sm={9}>
+ <Button
+ bsSize="large"
+ bsStyle="primary"
+ onClick={this.toggleFixupModal}
+
+ Run
Fixup Task
+ </Button>
+ </Col>
+ </Row>
+ </PluginBasicConfig>
</div>
);
}
diff --git a/src/cockpit/389-console/src/lib/plugins/pluginBasicConfig.jsx
b/src/cockpit/389-console/src/lib/plugins/pluginBasicConfig.jsx
index a61356e..ae37334 100644
--- a/src/cockpit/389-console/src/lib/plugins/pluginBasicConfig.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/pluginBasicConfig.jsx
@@ -43,7 +43,9 @@ class PluginBasicConfig extends React.Component {
currentPluginId: "",
currentPluginVendor: "",
currentPluginVersion: "",
- currentPluginDescription: ""
+ currentPluginDescription: "",
+ currentPluginDependsOnType: "",
+ currentPluginDependsOnNamed: ""
};
}
@@ -62,9 +64,7 @@ class PluginBasicConfig extends React.Component {
addNotification,
toggleLoadingHandler
} = this.props;
- const new_status = this.state.currentPluginEnabled
- ? "disable"
- : "enable";
+ const new_status = this.state.currentPluginEnabled ? "disable" :
"enable";
const cmd = [
"dsconf",
"-j",
@@ -76,11 +76,7 @@ class PluginBasicConfig extends React.Component {
toggleLoadingHandler();
this.setState({ disableSwitch: true });
- log_cmd(
- "handleSwitchChange",
- "Switch plugin states from the plugin tab",
- cmd
- );
+ log_cmd("handleSwitchChange", "Switch plugin states from the
plugin tab", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
@@ -88,7 +84,8 @@ class PluginBasicConfig extends React.Component {
pluginListHandler();
addNotification(
"success",
- `${pluginName} plugin was successfully ${new_status}d`
+ `${pluginName} plugin was successfully ${new_status}d.
+ Please, restart the instance.`
);
toggleLoadingHandler();
})
@@ -104,9 +101,7 @@ class PluginBasicConfig extends React.Component {
updateFields() {
if (this.props.rows.length > 0) {
- const pluginRow = this.props.rows.find(
- row => row.cn[0] === this.props.cn
- );
+ const pluginRow = this.props.rows.find(row => row.cn[0] ===
this.props.cn);
this.setState({
currentPluginType: pluginRow["nsslapd-pluginType"][0],
@@ -115,8 +110,15 @@ class PluginBasicConfig extends React.Component {
currentPluginId: pluginRow["nsslapd-pluginId"][0],
currentPluginVendor: pluginRow["nsslapd-pluginVendor"][0],
currentPluginVersion: pluginRow["nsslapd-pluginVersion"][0],
- currentPluginDescription:
- pluginRow["nsslapd-pluginDescription"][0]
+ currentPluginDescription:
pluginRow["nsslapd-pluginDescription"][0],
+ currentPluginDependsOnType:
+ pluginRow["nsslapd-plugin-depends-on-type"] === undefined
+ ? ""
+ : pluginRow["nsslapd-plugin-depends-on-type"][0],
+ currentPluginDependsOnNamed:
+ pluginRow["nsslapd-plugin-depends-on-named"] === undefined
+ ? ""
+ : pluginRow["nsslapd-plugin-depends-on-named"][0]
});
}
this.updateSwitch();
@@ -124,9 +126,7 @@ class PluginBasicConfig extends React.Component {
updateSwitch() {
if (this.props.rows.length > 0) {
- const pluginRow = this.props.rows.find(
- row => row.cn[0] === this.props.cn
- );
+ const pluginRow = this.props.rows.find(row => row.cn[0] ===
this.props.cn);
var pluginEnabled;
if (pluginRow["nsslapd-pluginEnabled"][0] === "on") {
@@ -158,19 +158,21 @@ class PluginBasicConfig extends React.Component {
currentPluginVendor,
currentPluginVersion,
currentPluginDescription,
+ currentPluginDependsOnType,
+ currentPluginDependsOnNamed,
disableSwitch
} = this.state;
const modalFieldsCol1 = {
currentPluginType: this.state.currentPluginType,
currentPluginPath: this.state.currentPluginPath,
- currentPluginInitfunc: this.state.currentPluginInitfunc,
- currentPluginId: this.state.currentPluginId
+ currentPluginInitfunc: this.state.currentPluginInitfunc
};
const modalFieldsCol2 = {
currentPluginVendor: this.state.currentPluginVendor,
currentPluginVersion: this.state.currentPluginVersion,
- currentPluginDescription: this.state.currentPluginDescription
+ currentPluginDescription: this.state.currentPluginDescription,
+ currentPluginId: this.state.currentPluginId
};
return (
<div>
@@ -184,11 +186,10 @@ class PluginBasicConfig extends React.Component {
</h3>
</Col>
<Col smOffset={1} sm={3}>
- <FormGroup
- key="switchPluginStatus"
- controlId="switchPluginStatus"
-
-
<ControlLabel className="toolbar-pf-find ds-float-left ds-right-indent">
+ <FormGroup key="switchPluginStatus"
controlId="switchPluginStatus">
+ <ControlLabel
+ className="toolbar-pf-find ds-float-left
ds-right-indent"
+
Status
</ControlLabel>
<Switch
@@ -196,11 +197,7 @@ class PluginBasicConfig extends React.Component {
title="normal"
id="bsSize-example"
value={currentPluginEnabled}
- onChange={() =>
- this.handleSwitchChange(
- currentPluginEnabled
- )
- }
+ onChange={() =>
this.handleSwitchChange(currentPluginEnabled)}
animate={false}
disabled={disableSwitch}
/>
@@ -213,94 +210,100 @@ class PluginBasicConfig extends React.Component {
<Row>
<Col sm={4}>
<Form horizontal>
- {Object.entries(modalFieldsCol1).map(
- ([id, value]) => (
- <FormGroup
- key={id}
- controlId={id}
- disabled={false}
-
-
<Col
- componentClass={ControlLabel}
- sm={4}
-
-
Plugin{" "}
- {id.replace(
- "currentPlugin",
- ""
- )}
- </Col>
- <Col sm={8}>
- <FormControl
- type="text"
- value={value}
- onChange={
- this.handleFieldChange
- }
- />
- </Col>
- </FormGroup>
- )
- )}
+ {Object.entries(modalFieldsCol1).map(([id, value]) =>
(
+ <FormGroup key={id} controlId={id}
disabled={false}>
+ <Col componentClass={ControlLabel} sm={6}>
+ {this.props.memberOfAttr} Plugin{"
"}
+ {id.replace("currentPlugin",
"")}
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+ value={value}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ ))}
+ <FormGroup
+ key="currentPluginDependsOnType"
+ controlId="currentPluginDependsOnType"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={6}>
+ Plugin Depends On Type
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+
value={this.state.currentPluginDependsOnType}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="currentPluginDependsOnNamed"
+ controlId="currentPluginDependsOnNamed"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={6}>
+ Plugin Depends On Named
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+
value={this.state.currentPluginDependsOnNamed}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
</Form>
</Col>
<Col sm={4}>
<Form horizontal>
- {Object.entries(modalFieldsCol2).map(
- ([id, value]) => (
- <FormGroup
- key={id}
- controlId={id}
- disabled={false}
-
-
<Col
- componentClass={ControlLabel}
- sm={4}
-
-
Plugin{" "}
- {id.replace(
- "currentPlugin",
- ""
- )}
- </Col>
- <Col sm={8}>
- <FormControl
- type="text"
- value={value}
- onChange={
- this.handleFieldChange
- }
- />
- </Col>
- </FormGroup>
- )
- )}
+ {Object.entries(modalFieldsCol2).map(([id, value]) =>
(
+ <FormGroup key={id} controlId={id}
disabled={false}>
+ <Col componentClass={ControlLabel} sm={5}>
+ Plugin {id.replace("currentPlugin",
"")}
+ </Col>
+ <Col sm={7}>
+ <FormControl
+ type="text"
+ value={value}
+ onChange={this.handleFieldChange}
+ />
+ </Col>
+ </FormGroup>
+ ))}
</Form>
</Col>
</Row>
- <Row>
- <Col smOffset={7} sm={1}>
- <Button
- bsSize="large"
- bsStyle="primary"
- onClick={() =>
- this.props.savePluginHandler({
- name: this.props.cn,
- type: currentPluginType,
- path: currentPluginPath,
- initfunc: currentPluginInitfunc,
- id: currentPluginId,
- vendor: currentPluginVendor,
- version: currentPluginVersion,
- description: currentPluginDescription
- })
- }
-
-
Save Config
- </Button>
- </Col>
- </Row>
</CustomCollapse>
+ <Row>
+ <Col smOffset={7} sm={1}>
+ <Button
+ bsSize="large"
+ bsStyle="primary"
+ onClick={() =>
+ this.props.savePluginHandler({
+ name: this.props.cn,
+ type: currentPluginType,
+ path: currentPluginPath,
+ initfunc: currentPluginInitfunc,
+ id: currentPluginId,
+ vendor: currentPluginVendor,
+ version: currentPluginVersion,
+ description: currentPluginDescription,
+ dependsOnType: currentPluginDependsOnType,
+ dependsOnNamed: currentPluginDependsOnNamed,
+ specificPluginCMD: this.props.specificPluginCMD
+ })
+ }
+
+ Save
Config
+ </Button>
+ </Col>
+ </Row>
</div>
);
}
@@ -313,6 +316,7 @@ PluginBasicConfig.propTypes = {
cn: PropTypes.string,
pluginName: PropTypes.string,
cmdName: PropTypes.string,
+ specificPluginCMD: PropTypes.array,
savePluginHandler: PropTypes.func,
pluginListHandler: PropTypes.func,
addNotification: PropTypes.func,
@@ -325,6 +329,7 @@ PluginBasicConfig.defaultProps = {
cn: "",
pluginName: "",
cmdName: "",
+ specificPluginCMD: [],
savePluginHandler: noop,
pluginListHandler: noop,
addNotification: noop,
diff --git a/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx
b/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx
index 2572475..d8358e9 100644
--- a/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx
+++ b/src/cockpit/389-console/src/lib/plugins/pluginModal.jsx
@@ -16,18 +16,14 @@ import "../../css/ds.css";
class PluginEditModal extends React.Component {
render() {
- const modalFields = {
- currentPluginType: this.props.currentPluginType,
- currentPluginPath: this.props.currentPluginPath,
- currentPluginInitfunc: this.props.currentPluginInitfunc,
- currentPluginId: this.props.currentPluginId,
- currentPluginVendor: this.props.currentPluginVendor,
- currentPluginVersion: this.props.currentPluginVersion,
- currentPluginDescription: this.props.currentPluginDescription
- };
const {
showModal,
closeHandler,
+ handleChange,
+ handleSwitchChange,
+ savePluginHandler
+ } = this.props;
+ const {
currentPluginName,
currentPluginEnabled,
currentPluginType,
@@ -37,10 +33,19 @@ class PluginEditModal extends React.Component {
currentPluginVendor,
currentPluginVersion,
currentPluginDescription,
- handleChange,
- handleSwitchChange,
- savePluginHandler
- } = this.props;
+ currentPluginDependsOnType,
+ currentPluginDependsOnNamed
+ } = this.props.pluginData;
+ const modalFields = {
+ currentPluginType: currentPluginType,
+ currentPluginPath: currentPluginPath,
+ currentPluginInitfunc: currentPluginInitfunc,
+ currentPluginId: currentPluginId,
+ currentPluginVendor: currentPluginVendor,
+ currentPluginVersion: currentPluginVersion,
+ currentPluginDescription: currentPluginDescription
+ };
+
return (
<Modal show={showModal} onHide={closeHandler}>
<div className="ds-no-horizontal-scrollbar">
@@ -53,9 +58,7 @@ class PluginEditModal extends React.Component {
<Icon type="pf" name="close" />
</button>
- <Modal.Title>
- Edit Plugin - {currentPluginName}
- </Modal.Title>
+ <Modal.Title>Edit Plugin -
{currentPluginName}</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form horizontal>
@@ -64,34 +67,26 @@ class PluginEditModal extends React.Component {
controlId="currentPluginEnabled"
disabled={false}
-
<Col componentClass={ControlLabel} sm={4}>
+ <Col componentClass={ControlLabel} sm={6}>
Plugin Status
</Col>
- <Col sm={7}>
+ <Col sm={6}>
<Switch
bsSize="normal"
title="normal"
id="pluginEnableSwitch"
value={currentPluginEnabled}
- onChange={() =>
- handleSwitchChange(
- currentPluginEnabled
- )
- }
+ onChange={() =>
handleSwitchChange(currentPluginEnabled)}
animate={false}
/>
</Col>
</FormGroup>
{Object.entries(modalFields).map(([id, value]) => (
- <FormGroup
- key={id}
- controlId={id}
- disabled={false}
-
-
<Col componentClass={ControlLabel} sm={4}>
+ <FormGroup key={id} controlId={id}
disabled={false}>
+ <Col componentClass={ControlLabel} sm={6}>
Plugin {id.replace("currentPlugin",
"")}
</Col>
- <Col sm={7}>
+ <Col sm={6}>
<FormControl
type="text"
value={value}
@@ -100,29 +95,61 @@ class PluginEditModal extends React.Component {
</Col>
</FormGroup>
))}
+ <FormGroup
+ key="currentPluginDependsOnType"
+ controlId="currentPluginDependsOnType"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={6}>
+ Plugin Depends On Type
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+ value={currentPluginDependsOnType}
+ onChange={handleChange}
+ />
+ </Col>
+ </FormGroup>
+ <FormGroup
+ key="currentPluginDependsOnNamed"
+ controlId="currentPluginDependsOnNamed"
+ disabled={false}
+
+
<Col componentClass={ControlLabel} sm={6}>
+ Plugin Depends On Type
+ </Col>
+ <Col sm={6}>
+ <FormControl
+ type="text"
+ value={currentPluginDependsOnNamed}
+ onChange={handleChange}
+ />
+ </Col>
+ </FormGroup>
</Form>
</Modal.Body>
- <Modal.Footer className="ds-modal-footer">
- <Button
- bsStyle="default"
- className="btn-cancel"
- onClick={closeHandler}
-
+
<Modal.Footer>
+ <Button bsStyle="default"
className="btn-cancel" onClick={closeHandler}>
Cancel
</Button>
<Button
bsStyle="primary"
- onClick={() => savePluginHandler({
- name: currentPluginName,
- enabled: currentPluginEnabled,
- type: currentPluginType,
- path: currentPluginPath,
- initfunc: currentPluginInitfunc,
- id: currentPluginId,
- vendor: currentPluginVendor,
- version: currentPluginVersion,
- description: currentPluginDescription
- })}
+ onClick={() =>
+ savePluginHandler({
+ name: currentPluginName,
+ enabled: currentPluginEnabled,
+ type: currentPluginType,
+ path: currentPluginPath,
+ initfunc: currentPluginInitfunc,
+ id: currentPluginId,
+ vendor: currentPluginVendor,
+ version: currentPluginVersion,
+ description: currentPluginDescription,
+ dependsOnType: currentPluginDependsOnType,
+ dependsOnNamed: currentPluginDependsOnNamed
+ })
+ }
Save
</Button>
@@ -136,15 +163,19 @@ class PluginEditModal extends React.Component {
PluginEditModal.propTypes = {
handleChange: PropTypes.func,
handleSwitchChange: PropTypes.func,
- currentPluginName: PropTypes.string,
- currentPluginType: PropTypes.string,
- currentPluginEnabled: PropTypes.bool,
- currentPluginPath: PropTypes.string,
- currentPluginInitfunc: PropTypes.string,
- currentPluginId: PropTypes.string,
- currentPluginVendor: PropTypes.string,
- currentPluginVersion: PropTypes.string,
- currentPluginDescription: PropTypes.string,
+ pluginData: PropTypes.exact({
+ currentPluginName: PropTypes.string,
+ currentPluginType: PropTypes.string,
+ currentPluginEnabled: PropTypes.bool,
+ currentPluginPath: PropTypes.string,
+ currentPluginInitfunc: PropTypes.string,
+ currentPluginId: PropTypes.string,
+ currentPluginVendor: PropTypes.string,
+ currentPluginVersion: PropTypes.string,
+ currentPluginDescription: PropTypes.string,
+ currentPluginDependsOnType: PropTypes.string,
+ currentPluginDependsOnNamed: PropTypes.string
+ }),
closeHandler: PropTypes.func,
savePluginHandler: PropTypes.func,
showModal: PropTypes.bool
@@ -153,15 +184,19 @@ PluginEditModal.propTypes = {
PluginEditModal.defaultProps = {
handleChange: noop,
handleSwitchChange: noop,
- currentPluginName: "",
- currentPluginType: "",
- currentPluginEnabled: false,
- currentPluginPath: "",
- currentPluginInitfunc: "",
- currentPluginId: "",
- currentPluginVendor: "",
- currentPluginVersion: "",
- currentPluginDescription: "",
+ pluginData: {
+ currentPluginName: "",
+ currentPluginType: "",
+ currentPluginEnabled: false,
+ currentPluginPath: "",
+ currentPluginInitfunc: "",
+ currentPluginId: "",
+ currentPluginVendor: "",
+ currentPluginVersion: "",
+ currentPluginDescription: "",
+ currentPluginDependsOnType: "",
+ currentPluginDependsOnNamed: ""
+ },
closeHandler: noop,
savePluginHandler: noop,
showModal: false
diff --git a/src/cockpit/389-console/src/plugins.jsx
b/src/cockpit/389-console/src/plugins.jsx
index 7afb619..2b455ba 100644
--- a/src/cockpit/389-console/src/plugins.jsx
+++ b/src/cockpit/389-console/src/plugins.jsx
@@ -69,7 +69,9 @@ export class Plugins extends React.Component {
currentPluginId: "",
currentPluginVendor: "",
currentPluginVersion: "",
- currentPluginDescription: ""
+ currentPluginDescription: "",
+ currentPluginDependsOnType: "",
+ currentPluginDependsOnNamed: ""
};
}
@@ -147,6 +149,14 @@ export class Plugins extends React.Component {
currentPluginVendor: rowData["nsslapd-pluginVendor"][0],
currentPluginVersion: rowData["nsslapd-pluginVersion"][0],
currentPluginDescription: rowData["nsslapd-pluginDescription"][0],
+ currentPluginDependsOnType:
+ rowData["nsslapd-plugin-depends-on-type"] === undefined
+ ? ""
+ : rowData["nsslapd-plugin-depends-on-type"][0],
+ currentPluginDependsOnNamed:
+ rowData["nsslapd-plugin-depends-on-named"] === undefined
+ ? ""
+ : rowData["nsslapd-plugin-depends-on-named"][0],
showPluginModal: true
});
}
@@ -179,7 +189,9 @@ export class Plugins extends React.Component {
}
savePlugin(data) {
- cmd = [
+ let nothingToSetErr = false;
+ let basicPluginSuccess = false;
+ let cmd = [
"dsconf",
"-j",
"ldapi://%2fvar%2frun%2fslapd-" + this.props.serverId +
".socket",
@@ -187,19 +199,23 @@ export class Plugins extends React.Component {
"edit",
data.name,
"--type",
- data.type,
+ data.type || "delete",
"--path",
- data.path,
+ data.path || "delete",
"--initfunc",
- data.initfunc,
+ data.initfunc || "delete",
"--id",
- data.id,
+ data.id || "delete",
"--vendor",
- data.vendor,
+ data.vendor || "delete",
"--version",
- data.version,
+ data.version || "delete",
"--description",
- data.description
+ data.description || "delete",
+ "--depends-on-type",
+ data.dependsOnType || "delete",
+ "--depends-on-named",
+ data.dependsOnNamed || "delete"
];
if ("enabled" in data) {
@@ -207,26 +223,80 @@ export class Plugins extends React.Component {
}
this.toggleLoading();
- log_cmd("savePlugin", "Edit the plugin from the modal form",
cmd);
+
+ log_cmd("savePlugin", "Edit the plugin", cmd);
cockpit
.spawn(cmd, { superuser: true, err: "message" })
.done(content => {
console.info("savePlugin", "Result", content);
+ basicPluginSuccess = true;
this.addNotification(
"success",
`Plugin ${data.name} was successfully modified`
);
- this.pluginList();
this.closePluginModal();
this.toggleLoading();
})
.fail(err => {
- this.addNotification(
- "error",
- `Error during plugin ${data.name} modification - ${err}`
- );
+ if (err.message.indexOf("nothing to set") >= 0) {
+ nothingToSetErr = true;
+ } else {
+ this.addNotification(
+ "error",
+ `${err.message} error during ${data.name} modification`
+ );
+ }
this.closePluginModal();
this.toggleLoading();
+ })
+ .always(() => {
+ if ("specificPluginCMD" in data) {
+ this.toggleLoading();
+ log_cmd(
+ "savePlugin",
+ "Edit the plugin from the plugin config tab",
+ data.specificPluginCMD
+ );
+ cockpit
+ .spawn(data.specificPluginCMD, {
+ superuser: true,
+ err: "message"
+ })
+ .done(content => {
+ // Notify success only one time
+ if (!basicPluginSuccess) {
+ this.addNotification(
+ "success",
+ `Plugin ${data.name} was successfully
modified`
+ );
+ }
+ this.pluginList();
+ this.toggleLoading();
+ console.info("savePlugin",
"Result", content);
+ })
+ .fail(err => {
+ if (
+ (err.message.indexOf(
+ "nothing to set"
+ ) >= 0 &&
+ nothingToSetErr) ||
+ err.message.indexOf("nothing to set") < 0
+ ) {
+ if (basicPluginSuccess) {
+ this.addNotification(
+ "success",
+ `Plugin ${data.name} was successfully
modified`
+ );
+ this.pluginList();
+ }
+ this.addNotification(
+ "error",
+ `${err.message} error during ${data.name}
modification`
+ );
+ }
+ this.toggleLoading();
+ });
+ }
});
}
@@ -235,10 +305,7 @@ export class Plugins extends React.Component {
allPlugins: {
name: "All Plugins",
component: (
- <PluginTable
- rows={this.state.rows}
- loadModalHandler={this.openPluginModal}
- />
+ <PluginTable rows={this.state.rows}
loadModalHandler={this.openPluginModal} />
)
},
accountPolicy: {
@@ -424,24 +491,20 @@ export class Plugins extends React.Component {
<Row className="clearfix">
<Col sm={2}>
<Nav bsStyle="pills" stacked>
- {Object.entries(selectPlugins).map(
- ([id, item]) => (
- <NavItem key={id} eventKey={id}>
- {item.name}
- </NavItem>
- )
- )}
+ {Object.entries(selectPlugins).map(([id, item]) => (
+ <NavItem key={id} eventKey={id}>
+ {item.name}
+ </NavItem>
+ ))}
</Nav>
</Col>
<Col sm={10}>
<Tab.Content animation={false}>
- {Object.entries(selectPlugins).map(
- ([id, item]) => (
- <Tab.Pane key={id} eventKey={id}>
- {item.component}
- </Tab.Pane>
- )
- )}
+ {Object.entries(selectPlugins).map(([id, item]) => (
+ <Tab.Pane key={id} eventKey={id}>
+ {item.component}
+ </Tab.Pane>
+ ))}
</Tab.Content>
</Col>
</Row>
@@ -449,17 +512,19 @@ export class Plugins extends React.Component {
<PluginEditModal
handleChange={this.handleFieldChange}
handleSwitchChange={this.handleSwitchChange}
- currentPluginName={this.state.currentPluginName}
- currentPluginType={this.state.currentPluginType}
- currentPluginEnabled={this.state.currentPluginEnabled}
- currentPluginPath={this.state.currentPluginPath}
- currentPluginInitfunc={this.state.currentPluginInitfunc}
- currentPluginId={this.state.currentPluginId}
- currentPluginVendor={this.state.currentPluginVendor}
- currentPluginVersion={this.state.currentPluginVersion}
- currentPluginDescription={
- this.state.currentPluginDescription
- }
+ pluginData={{
+ currentPluginName: this.state.currentPluginName,
+ currentPluginType: this.state.currentPluginType,
+ currentPluginEnabled: this.state.currentPluginEnabled,
+ currentPluginPath: this.state.currentPluginPath,
+ currentPluginInitfunc: this.state.currentPluginInitfunc,
+ currentPluginId: this.state.currentPluginId,
+ currentPluginVendor: this.state.currentPluginVendor,
+ currentPluginVersion: this.state.currentPluginVersion,
+ currentPluginDescription: this.state.currentPluginDescription,
+ currentPluginDependsOnType:
this.state.currentPluginDependsOnType,
+ currentPluginDependsOnNamed:
this.state.currentPluginDependsOnNamed
+ }}
closeHandler={this.closePluginModal}
showModal={this.state.showPluginModal}
savePluginHandler={this.savePlugin}
diff --git a/src/cockpit/389-console/src/static/Typeahead.css
b/src/cockpit/389-console/src/static/Typeahead.css
new file mode 100644
index 0000000..0f728f9
--- /dev/null
+++ b/src/cockpit/389-console/src/static/Typeahead.css
@@ -0,0 +1,256 @@
+.rbt {
+ outline: none;
+}
+
+.rbt-menu {
+ margin-bottom: 2px;
+}
+
+.rbt-menu > li a {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.rbt-menu > li a:focus {
+ outline: none;
+}
+
+.rbt-menu-pagination-option {
+ text-align: center;
+}
+
+.rbt .rbt-input-main::-ms-clear {
+ display: none;
+}
+
+.rbt-input-multi {
+ cursor: text;
+ overflow: hidden;
+ position: relative;
+ height: auto;
+}
+
+.rbt-input-multi.focus {
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233,
0.6);
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233,
0.6);
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
+ border-color: #66afe9;
+ outline: 0;
+}
+
+.rbt-input-multi.form-control[disabled] {
+ background-color: #e9ecef;
+ opacity: 1;
+}
+
+.rbt-input-multi input::-moz-placeholder {
+ color: #999;
+ opacity: 1;
+}
+
+.rbt-input-multi input:-ms-input-placeholder {
+ color: #999;
+}
+
+.rbt-input-multi input::-webkit-input-placeholder {
+ color: #999;
+}
+
+.rbt-input-multi .rbt-input-wrapper {
+ margin-bottom: -4px;
+ margin-top: -1px;
+ overflow: hidden;
+}
+
+.rbt-input-multi .rbt-input-main {
+ height: 20px;
+ margin: 1px 0 4px;
+}
+
+.rbt-input-multi .rbt-input-hint-container {
+ display: inline-block;
+}
+
+.rbt-input-multi.input-lg .rbt-input-main, .rbt-input-multi.form-control-lg
.rbt-input-main {
+ height: 24px;
+}
+
+.rbt-input-multi.input-sm .rbt-input-main, .rbt-input-multi.form-control-sm
.rbt-input-main {
+ height: 18px;
+}
+
+.rbt-close {
+ z-index: 1;
+}
+
+.rbt-close-lg {
+ font-size: 24px;
+}
+
+.rbt-token {
+ background-color: #e7f4ff;
+ border: 0;
+ border-radius: 2px;
+ color: #1f8dd6;
+ display: inline-block;
+ line-height: 1em;
+ margin: 0 3px 3px 0;
+ padding: 4px 7px;
+ position: relative;
+}
+
+.rbt-token-disabled {
+ background-color: #ddd;
+ color: #888;
+ pointer-events: none;
+}
+
+.rbt-token-removeable {
+ cursor: pointer;
+ padding-right: 21px;
+}
+
+.rbt-token-active {
+ background-color: #1f8dd6;
+ color: #fff;
+ outline: none;
+ text-decoration: none;
+}
+
+.rbt-token .rbt-token-remove-button {
+ bottom: 0;
+ color: inherit;
+ font-size: inherit;
+ font-weight: normal;
+ opacity: 1;
+ outline: none;
+ padding: 3px 7px;
+ position: absolute;
+ right: 0;
+ text-shadow: none;
+ top: -2px;
+}
+
+.rbt-loader {
+ -webkit-animation: loader-animation 600ms infinite linear;
+ -o-animation: loader-animation 600ms infinite linear;
+ animation: loader-animation 600ms infinite linear;
+ border: 1px solid #d5d5d5;
+ border-radius: 50%;
+ border-top-color: #1f8dd6;
+ display: block;
+ height: 16px;
+ width: 16px;
+}
+
+.rbt-loader-lg {
+ height: 20px;
+ width: 20px;
+}
+
+.rbt-aux {
+ display: -webkit-box;
+ display: -moz-box;
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+ align-items: center;
+ bottom: 0;
+ justify-content: center;
+ pointer-events: none;
+ /* Don't block clicks on the input */
+ position: absolute;
+ right: 0;
+ top: 0;
+ width: 34px;
+}
+
+.rbt-aux-lg {
+ width: 46px;
+}
+
+.rbt-aux .rbt-close {
+ margin-top: -4px;
+ pointer-events: auto;
+ /* Override pointer-events: none; above */
+}
+
+.has-aux .rbt-input {
+ padding-right: 34px;
+}
+
+.rbt-highlight-text {
+ background-color: inherit;
+ color: inherit;
+ font-weight: bold;
+ padding: 0;
+}
+
+/* Input Groups */
+.input-group > .rbt {
+ -webkit-box-flex: 1;
+ -moz-box-flex: 1;
+ -webkit-flex: 1;
+ -ms-flex: 1;
+ flex: 1;
+}
+
+.input-group > .rbt .rbt-input-hint-container {
+ display: -webkit-box;
+ display: -moz-box;
+ display: -ms-flexbox;
+ display: -webkit-flex;
+ display: flex;
+}
+
+.input-group > .rbt .rbt-input-hint {
+ z-index: 5;
+}
+
+.input-group > .rbt .rbt-aux {
+ z-index: 5;
+}
+
+.input-group > .rbt:not(:first-child) .form-control {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.input-group > .rbt:not(:last-child) .form-control {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+/* Validation States */
+.has-error .rbt-input-multi.focus {
+ border-color: #843534;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #ce8483;
+}
+
+.has-warning .rbt-input-multi.focus {
+ border-color: #66512c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #c0a16b;
+}
+
+.has-success .rbt-input-multi.focus {
+ border-color: #2b542c;
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+ -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #67b168;
+}
+
+@keyframes loader-animation {
+ to {
+ transform: rotate(1turn);
+ }
+}
+
+@-webkit-keyframes loader-animation {
+ to {
+ -webkit-transform: rotate(1turn);
+ }
+}
diff --git a/src/cockpit/389-console/webpack.config.js
b/src/cockpit/389-console/webpack.config.js
index 6d7cbec..2387cd9 100644
--- a/src/cockpit/389-console/webpack.config.js
+++ b/src/cockpit/389-console/webpack.config.js
@@ -6,24 +6,22 @@ const webpack = require("webpack");
const CompressionPlugin = require("compression-webpack-plugin");
var externals = {
- "cockpit": "cockpit",
+ cockpit: "cockpit"
};
/* These can be overridden, typically from the Makefile.am */
const srcdir = (process.env.SRCDIR || __dirname) + path.sep + "src";
-const builddir = (process.env.SRCDIR || __dirname);
+const builddir = process.env.SRCDIR || __dirname;
const distdir = builddir + path.sep + "dist";
const section = process.env.ONLYDIR || null;
-const nodedir = path.resolve((process.env.SRCDIR || __dirname),
"node_modules");
+const nodedir = path.resolve(process.env.SRCDIR || __dirname, "node_modules");
/* A standard nodejs and webpack pattern */
-var production = process.env.NODE_ENV === 'production';
+var production = process.env.NODE_ENV === "production";
var info = {
entries: {
- "index": [
- "./index.es6"
- ]
+ index: ["./index.es6"]
},
files: [
"backend.html",
@@ -46,14 +44,14 @@ var info = {
"servers.html",
"servers.js",
"static",
- "manifest.json",
- ],
+ "manifest.json"
+ ]
};
var output = {
path: distdir,
filename: "[name].js",
- sourceMapFilename: "[file].map",
+ sourceMapFilename: "[file].map"
};
/*
@@ -67,8 +65,7 @@ var output = {
function vpath(/* ... */) {
var filename = Array.prototype.join.call(arguments, path.sep);
var expanded = builddir + path.sep + filename;
- if (fs.existsSync(expanded))
- return expanded;
+ if (fs.existsSync(expanded)) return expanded;
expanded = srcdir + path.sep + filename;
return expanded;
}
@@ -81,10 +78,8 @@ Object.keys(info.entries).forEach(function(key) {
}
info.entries[key] = info.entries[key].map(function(value) {
- if (value.indexOf("/") === -1)
- return value;
- else
- return vpath(value);
+ if (value.indexOf("/") === -1) return value;
+ else return vpath(value);
});
});
@@ -96,26 +91,25 @@ info.files.forEach(function(value) {
});
info.files = files;
-var plugins = [
- new copy(info.files),
- new extract("[name].css")
-];
+var plugins = [new copy(info.files), new extract("[name].css")];
/* Only minimize when in production mode */
if (production) {
/* Rename output files when minimizing */
output.filename = "[name].min.js";
- plugins.unshift(new CompressionPlugin({
- asset: "[path].gz[query]",
- test: /\.(js|html)$/,
- minRatio: 0.9,
- deleteOriginalAssets: true
- }));
+ plugins.unshift(
+ new CompressionPlugin({
+ asset: "[path].gz[query]",
+ test: /\.(js|html)$/,
+ minRatio: 0.9,
+ deleteOriginalAssets: true
+ })
+ );
}
module.exports = {
- mode: production ? 'production' : 'development',
+ mode: production ? "production" : "development",
entry: info.entries,
externals: externals,
output: output,
@@ -123,42 +117,44 @@ module.exports = {
module: {
rules: [
{
- enforce: 'pre',
+ enforce: "pre",
exclude: /node_modules/,
- loader: 'eslint-loader',
+ loader: "eslint-loader",
test: /\.jsx$/
},
{
- enforce: 'pre',
+ enforce: "pre",
exclude: /node_modules/,
- loader: 'eslint-loader',
+ loader: "eslint-loader",
test: /\.es6$/
},
{
exclude: /node_modules/,
- loader: 'babel-loader',
+ loader: "babel-loader",
test: /\.js$/
},
{
exclude: /node_modules/,
- loader: 'babel-loader',
+ loader: "babel-loader",
test: /\.jsx$/
},
{
exclude: /node_modules/,
- loader: 'babel-loader',
+ loader: "babel-loader",
test: /\.es6$/
},
{
+ // Transform our own .css files with PostCSS and CSS-modules
+ test: /\.css$/,
exclude: /node_modules/,
- loader: extract.extract('css-loader!sass-loader'),
- test: /\.scss$/
+ use: ['style-loader', 'css-loader'],
},
{
test: /\.css$/,
- use: [ 'style-loader', 'css-loader' ]
+ include: /node_modules/,
+ use: ['style-loader', 'css-loader'],
}
]
},
plugins: plugins
-}
+};
diff --git a/src/lib389/lib389/_mapped_object.py b/src/lib389/lib389/_mapped_object.py
index e1f9adb..06a2821 100644
--- a/src/lib389/lib389/_mapped_object.py
+++ b/src/lib389/lib389/_mapped_object.py
@@ -270,7 +270,14 @@ class DSLdapObject(DSLogging):
:param *args: tuples of key,value to replace.
:type *args: (str, str)
"""
- mods = list(map(lambda t: (ldap.MOD_REPLACE, ensure_str(t[0]),
ensure_bytes(t[1])), args))
+
+ mods = []
+ for arg in args:
+ if isinstance(arg[1], list):
+ value = ensure_list_bytes(arg[1])
+ else:
+ value = [ensure_bytes(arg[1])]
+ mods.append((ldap.MOD_REPLACE, ensure_str(arg[0]), value))
return self._instance.modify_ext_s(self._dn, mods,
serverctrls=self._server_controls, clientctrls=self._client_controls)
# This needs to work on key + val, and key
@@ -371,7 +378,7 @@ class DSLdapObject(DSLogging):
def apply_mods(self, mods):
"""Perform modification operation using several mods at once
- :param mods: [(action, key, value),]
+ :param mods: [(action, key, value),] or [(ldap.MOD_DELETE, key),]
:type mods: list of tuples
:raises: ValueError - if a provided mod op is invalid
"""
@@ -381,25 +388,25 @@ class DSLdapObject(DSLogging):
if len(mod) < 2:
# Error
raise ValueError('Not enough arguments in the mod op')
- elif len(mod) == 2: # no action
- action = ldap.MOD_REPLACE
- key, value = mod
+ elif len(mod) == 2: # delete all attributes action
+ action, key = mod
+ if action != ldap.MOD_DELETE:
+ raise ValueError('Not enough arguments in the mod op')
+ mod_list.append((action, key, None))
elif len(mod) == 3:
action, key, value = mod
if action != ldap.MOD_REPLACE and \
action != ldap.MOD_ADD and \
action != ldap.MOD_DELETE:
raise ValueError('Invalid mod action(%s)' % str(action))
+ if isinstance(value, list):
+ value = ensure_list_bytes(value)
+ else:
+ value = [ensure_bytes(value)]
+ mod_list.append((action, key, value))
else:
# Error too many items
raise ValueError('Too many arguments in the mod op')
-
- if isinstance(value, list):
- value = ensure_list_bytes(value)
- else:
- value = [ensure_bytes(value)]
-
- mod_list.append((action, key, value))
return self._instance.modify_ext_s(self._dn, mod_list,
serverctrls=self._server_controls, clientctrls=self._client_controls)
@classmethod
diff --git a/src/lib389/lib389/cli_conf/__init__.py
b/src/lib389/lib389/cli_conf/__init__.py
index a969724..1ba3b4a 100644
--- a/src/lib389/lib389/cli_conf/__init__.py
+++ b/src/lib389/lib389/cli_conf/__init__.py
@@ -5,6 +5,67 @@
# License: GPL (version 3 or any later version).
# See LICENSE for details.
# --- END COPYRIGHT BLOCK ---
+import ldap
+from lib389 import ensure_list_str
+
+
+def _args_to_attrs(args, arg_to_attr):
+ attrs = {}
+ for arg in vars(args):
+ val = getattr(args, arg)
+ if arg in arg_to_attr and val is not None:
+ attrs[arg_to_attr[arg]] = val
+ elif arg == 'DN':
+ # Extract RDN from the DN
+ attribute = ldap.dn.str2dn(val)[0][0][0]
+ value = ldap.dn.str2dn(val)[0][0][1]
+ attrs[attribute] = value
+ return attrs
+
+
+def generic_object_add(dsldap_object, log, args, arg_to_attr, props={}):
+ """Create an entry using DSLdapObject interface
+
+ dsldap_object should be a single instance of DSLdapObject with a set dn
+ """
+
+ log = log.getChild('generic_object_add')
+ # Gather the attributes
+ attrs = _args_to_attrs(args, arg_to_attr)
+ # Update the parameters (which should have at least 'cn') with arg
attributes
+ props.update({attr: value for (attr, value) in attrs.items() if value !=
""})
+ new_object = dsldap_object.create(properties=props)
+ log.info("Successfully created the %s", new_object.dn)
+
+
+def generic_object_edit(dsldap_object, log, args, arg_to_attr):
+ """Create an entry using DSLdapObject interface
+
+ dsldap_object should be a single instance of DSLdapObject with a set dn
+ """
+
+ log = log.getChild('generic_object_edit')
+ # Gather the attributes
+ attrs = _args_to_attrs(args, arg_to_attr)
+ existing_attributes = dsldap_object.get_all_attrs()
+
+ modlist = []
+ for attr, value in attrs.items():
+ # Delete the attribute only if the user set it to 'delete' value
+ if value in ("delete", ["delete"]):
+ if attr in existing_attributes:
+ modlist.append((ldap.MOD_DELETE, attr))
+ else:
+ if not isinstance(value, list):
+ value = [value]
+ if not (attr in existing_attributes and value ==
ensure_list_str(existing_attributes[attr])):
+ modlist.append((ldap.MOD_REPLACE, attr, value))
+ if len(modlist) > 0:
+ dsldap_object.apply_mods(modlist)
+ log.info("Successfully changed the %s", dsldap_object.dn)
+ else:
+ raise ValueError("There is nothing to set in the %s plugin entry" %
dsldap_object.dn)
+
def generic_show(inst, basedn, log, args):
"""Display plugin configuration."""
@@ -15,27 +76,27 @@ def generic_show(inst, basedn, log, args):
def generic_enable(inst, basedn, log, args):
plugin = args.plugin_cls(inst)
if plugin.status():
- print("Plugin '%s' already enabled" % plugin.rdn)
+ print("Plugin '%s' already enabled", plugin.rdn)
else:
plugin.enable()
- print("Enabled plugin '%s'" % plugin.rdn)
+ print("Enabled plugin '%s'", plugin.rdn)
def generic_disable(inst, basedn, log, args):
plugin = args.plugin_cls(inst)
if not plugin.status():
- print("Plugin '%s' already disabled " % plugin.rdn)
+ print("Plugin '%s' already disabled", plugin.rdn)
else:
plugin.disable()
- print("Disabled plugin '%s'" % plugin.rdn)
+ print("Disabled plugin '%s'", plugin.rdn)
def generic_status(inst, basedn, log, args):
plugin = args.plugin_cls(inst)
if plugin.status() is True:
- print("Plugin '%s' is enabled" % plugin.rdn)
+ print("Plugin '%s' is enabled", plugin.rdn)
else:
- print("Plugin '%s' is disabled" % plugin.rdn)
+ print("Plugin '%s' is disabled", plugin.rdn)
def add_generic_plugin_parsers(subparser, plugin_cls):
diff --git a/src/lib389/lib389/cli_conf/backend.py
b/src/lib389/lib389/cli_conf/backend.py
index c970e84..fdb5dd5 100644
--- a/src/lib389/lib389/cli_conf/backend.py
+++ b/src/lib389/lib389/cli_conf/backend.py
@@ -170,7 +170,7 @@ def backend_create(inst, basedn, log, args):
be = Backend(inst)
be.create(properties=props)
- print("The database was sucessfully created")
+ print("The database was successfully created")
def _recursively_del_backends(be):
@@ -197,7 +197,7 @@ def backend_delete(inst, basedn, log, args, warn=True):
_recursively_del_backends(be)
be.delete()
- print("The database, and any sub-suffixes, were sucessfully deleted")
+ print("The database, and any sub-suffixes, were successfully deleted")
def backend_import(inst, basedn, log, args):
@@ -307,7 +307,7 @@ def backend_set(inst, basedn, log, args):
be.enable()
if args.disable:
be.disable()
- print("The backend configuration was sucessfully updated")
+ print("The backend configuration was successfully updated")
def db_config_get(inst, basedn, log, args):
diff --git a/src/lib389/lib389/cli_conf/plugin.py b/src/lib389/lib389/cli_conf/plugin.py
index ea43a8d..5cc7c8c 100644
--- a/src/lib389/lib389/cli_conf/plugin.py
+++ b/src/lib389/lib389/cli_conf/plugin.py
@@ -13,6 +13,7 @@ from lib389.cli_base import (
_generic_get,
_get_arg,
)
+from lib389.cli_conf import generic_object_edit
from lib389.cli_conf.plugins import memberof as cli_memberof
from lib389.cli_conf.plugins import usn as cli_usn
from lib389.cli_conf.plugins import rootdn_ac as cli_rootdn_ac
@@ -31,6 +32,19 @@ SINGULAR = Plugin
MANY = Plugins
RDN = 'cn'
+arg_to_attr = {
+ 'initfunc': 'nsslapd-pluginInitfunc',
+ 'enabled': 'nsslapd-pluginEnabled',
+ 'path': 'nsslapd-pluginPath',
+ 'type': 'nsslapd-pluginType',
+ 'id': 'nsslapd-pluginId',
+ 'version': 'nsslapd-pluginVersion',
+ 'vendor': 'nsslapd-pluginVendor',
+ 'description': 'nsslapd-pluginDescription',
+ 'depends_on_type': 'nsslapd-plugin-depends-on-type',
+ 'depends_on_named': 'nsslapd-plugin-depends-on-named'
+}
+
def plugin_list(inst, basedn, log, args):
plugin_log = log.getChild('plugin_list')
@@ -77,25 +91,7 @@ def plugin_edit(inst, basedn, log, args):
rdn = _get_arg(args.selector, msg="Enter %s to retrieve" % RDN)
plugins = Plugins(inst)
plugin = plugins.get(rdn)
-
- if args.enabled is not None and args.enabled.lower() not in ["on",
"off"]:
- raise ValueError("Plugin enabled argument should be 'on' or
'off'")
-
- plugin_args = {'nsslapd-pluginInitfunc': args.initfunc,
- 'nsslapd-pluginEnabled': args.enabled,
- 'nsslapd-pluginPath': args.path,
- 'nsslapd-pluginType': args.type,
- 'nsslapd-pluginId': args.id,
- 'nsslapd-pluginVersion': args.version,
- 'nsslapd-pluginVendor': args.vendor,
- 'nsslapd-pluginDescription': args.description}
- mods = vaidate_args(plugin, plugin_args)
-
- if len(mods) > 0:
- plugin.replace_many(*mods)
- log.info("Successfully changed the plugin %s", rdn)
- else:
- raise ValueError("Nothing to change")
+ generic_object_edit(plugin, log, args, arg_to_attr)
def create_parser(subparsers):
@@ -128,11 +124,17 @@ def create_parser(subparsers):
edit_parser.set_defaults(func=plugin_edit)
edit_parser.add_argument('selector', nargs='?', help='The plugin
to edit')
edit_parser.add_argument('--type', help='The type of plugin.')
- edit_parser.add_argument('--enabled',
- help='Identifies whether or not the plugin is enabled.
It should have "on" or "off" values.')
+ edit_parser.add_argument('--enabled', choices=['on', 'off'],
+ help='Identifies whether or not the plugin is
enabled.')
edit_parser.add_argument('--path', help='The plugin library name (without
the library suffix).')
edit_parser.add_argument('--initfunc', help='An initialization function
of the plugin.')
edit_parser.add_argument('--id', help='The plugin ID.')
edit_parser.add_argument('--vendor', help='The vendor of plugin.')
edit_parser.add_argument('--version', help='The version of plugin.')
edit_parser.add_argument('--description', help='The description of the
plugin.')
+ edit_parser.add_argument('--depends-on-type',
+ help='All plug-ins with a type value which matches one
of the values '
+ 'in the following valid range will be started by
the server prior to this plug-in.')
+ edit_parser.add_argument('--depends-on-named',
+ help='The plug-in name matching one of the following
values will be '
+ 'started by the server prior to this plug-in')
diff --git a/src/lib389/lib389/cli_conf/plugins/memberof.py
b/src/lib389/lib389/cli_conf/plugins/memberof.py
index b9865a8..0ccbed3 100644
--- a/src/lib389/lib389/cli_conf/plugins/memberof.py
+++ b/src/lib389/lib389/cli_conf/plugins/memberof.py
@@ -7,199 +7,92 @@
# --- END COPYRIGHT BLOCK ---
import ldap
-
-from lib389.plugins import MemberOfPlugin
-from lib389.cli_conf import add_generic_plugin_parsers
-
-
-def manage_attr(inst, basedn, log, args):
- if args.value is not None:
- set_attr(inst, basedn, log, args)
- else:
- display_attr(inst, basedn, log, args)
-
-def display_attr(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- log.info(plugin.get_attr_formatted())
-
-def set_attr(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- try:
- plugin.set_attr(args.value)
- except ldap.UNWILLING_TO_PERFORM:
- log.error('Error: Illegal value "{}". Failed to
set.'.format(args.value))
- else:
- log.info('memberOfAttr set to "{}"'.format(args.value))
-
-def display_groupattr(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- log.info(plugin.get_groupattr_formatted())
-
-def add_groupattr(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- try:
- plugin.add_groupattr(args.value)
- except ldap.UNWILLING_TO_PERFORM:
- log.error('Error: Illegal value "{}". Failed to
add.'.format(args.value))
- except ldap.TYPE_OR_VALUE_EXISTS:
- log.info('Value "{}" already exists.'.format(args.value))
- else:
- log.info('successfully added memberOfGroupAttr value
"{}"'.format(args.value))
-
-def remove_groupattr(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- try:
- plugin.remove_groupattr(args.value)
- except ldap.UNWILLING_TO_PERFORM:
- log.error("Error: Failed to delete. memberOfGroupAttr is required.")
- except ldap.NO_SUCH_ATTRIBUTE:
- log.error('Error: Failed to delete. No value "{0}"
found.'.format(args.value))
- else:
- log.info('successfully removed memberOfGroupAttr value
"{}"'.format(args.value))
-
-def display_allbackends(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- val = plugin.get_allbackends_formatted()
- if not val:
- log.info("memberOfAllBackends is not set")
+from lib389.plugins import MemberOfPlugin, Plugins, MemberOfSharedConfig
+from lib389.cli_conf import add_generic_plugin_parsers, generic_object_edit,
generic_object_add
+
+arg_to_attr = {
+ 'initfunc': 'nsslapd-pluginInitfunc',
+ 'attr': 'memberOfAttr',
+ 'groupattr': 'memberOfGroupAttr',
+ 'allbackends': 'memberOfAllBackends',
+ 'skipnested': 'memberOfSkipNested',
+ 'scope': 'memberOfEntryScope',
+ 'exclude': 'memberOfEntryScopeExcludeSubtree',
+ 'autoaddoc': 'memberOfAutoAddOC',
+ 'config_entry': 'nsslapd-pluginConfigArea'
+}
+
+
+def memberof_edit(inst, basedn, log, args):
+ log = log.getChild('memberof_edit')
+ plugins = Plugins(inst)
+ plugin = plugins.get("MemberOf Plugin")
+ generic_object_edit(plugin, log, args, arg_to_attr)
+
+
+def memberof_add_config(inst, basedn, log, args):
+ log = log.getChild('memberof_add_config')
+ targetdn = args.DN
+ config = MemberOfSharedConfig(inst, targetdn)
+ generic_object_add(config, log, args, arg_to_attr)
+ plugins = Plugins(inst)
+ plugin = plugins.get("MemberOf Plugin")
+ plugin.replace('nsslapd-pluginConfigArea', config.dn)
+ log.info('MemberOf attribute nsslapd-pluginConfigArea (config-entry) '
+ 'was set in the main plugin config')
+
+
+def memberof_edit_config(inst, basedn, log, args):
+ log = log.getChild('memberof_edit_config')
+ targetdn = args.DN
+ config = MemberOfSharedConfig(inst, targetdn)
+ generic_object_edit(config, log, args, arg_to_attr)
+
+
+def memberof_show_config(inst, basedn, log, args):
+ log = log.getChild('memberof_show_config')
+ targetdn = args.DN
+ config = MemberOfSharedConfig(inst, targetdn)
+
+ if not config.exists():
+ raise ldap.NO_SUCH_OBJECT("Entry %s doesn't exists" % targetdn)
+ if args and args.json:
+ o_str = config.get_all_attrs_json()
+ print(o_str)
else:
- log.info(val)
+ print(config.display())
-def enable_allbackends(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- plugin.enable_allbackends()
- log.info("memberOfAllBackends enabled successfully")
-
-def disable_allbackends(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- plugin.disable_allbackends()
- log.info("memberOfAllBackends disabled successfully")
-def display_skipnested(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- val = plugin.get_skipnested_formatted()
- if not val:
- log.info("memberOfSkipNested is not set")
- else:
- log.info(val)
-
-def enable_skipnested(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- plugin.enable_skipnested()
- log.info("memberOfSkipNested set successfully")
+def memberof_del_config(inst, basedn, log, args):
+ log = log.getChild('memberof_del_config')
+ targetdn = args.DN
+ config = MemberOfSharedConfig(inst, targetdn)
+ config.delete()
+ log.info("Successfully deleted the %s", targetdn)
-def disable_skipnested(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- plugin.disable_skipnested()
- log.info("memberOfSkipNested unset successfully")
-
-def manage_autoaddoc(inst, basedn, log, args):
- if args.value == "del":
- remove_autoaddoc(inst, basedn, log, args)
- elif args.value is not None:
- set_autoaddoc(inst, basedn, log, args)
- else:
- display_autoaddoc(inst, basedn, log, args)
-
-def display_autoaddoc(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- val = plugin.get_autoaddoc_formatted()
- if not val:
- log.info("memberOfAutoAddOc is not set")
- else:
- log.info(val)
-
-def set_autoaddoc(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- d = {'nsmemberof': 'nsMemberOf', 'inetuser':
'inetUser', 'inetadmin': 'inetAdmin'}
- plugin.set_autoaddoc(d[args.value])
- log.info('memberOfAutoAddOc set to "{}"'.format(d[args.value]))
-
-def remove_autoaddoc(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- if not plugin.get_autoaddoc():
- log.info("memberOfAutoAddOc was not set")
- else:
- plugin.remove_autoaddoc()
- log.info("memberOfAutoAddOc attribute deleted")
-
-def display_scope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- val = plugin.get_entryscope_formatted()
- if not val:
- log.info("memberOfEntryScope is not set")
- else:
- log.info(val)
-
-def add_scope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- try:
- plugin.add_entryscope(args.value)
- except ldap.UNWILLING_TO_PERFORM as ex:
- if "is also listed as an exclude suffix" in
ex.args[0]['info']:
- log.error('Error: Include suffix ({0}) is also listed as an exclude
suffix.'.format(args.value))
- else:
- log.error('Error: Invalid DN "{}". Failed to
add.'.format(args.value))
- except ldap.TYPE_OR_VALUE_EXISTS:
- log.info('Value "{}" already exists.'.format(args.value))
- else:
- log.info('successfully added memberOfEntryScope value
"{}"'.format(args.value))
-
-def remove_scope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- try:
- plugin.remove_entryscope(args.value)
- except ldap.NO_SUCH_ATTRIBUTE:
- log.error('Error: Failed to delete. No value "{0}"
found.'.format(args.value))
- else:
- log.info('successfully removed memberOfEntryScope value
"{}"'.format(args.value))
-
-def remove_all_scope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- plugin.remove_all_entryscope()
- log.info('successfully removed all memberOfEntryScope values')
-
-def display_excludescope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- val = plugin.get_excludescope_formatted()
- if not val:
- log.info("memberOfEntryScopeExcludeSubtree is not set")
- else:
- log.info(val)
-
-def add_excludescope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- try:
- plugin.add_excludescope(args.value)
- except ldap.UNWILLING_TO_PERFORM as ex:
- if "is also listed as an exclude suffix" in
ex.args[0]['info']:
- log.error('Error: Suffix ({0}) is listed in entry
scope.'.format(args.value))
- else:
- log.error('Error: Invalid DN "{}". Failed to
add.'.format(args.value))
- except ldap.TYPE_OR_VALUE_EXISTS:
- log.info('Value "{}" already exists.'.format(args.value))
- else:
- log.info('successfully added memberOfEntryScopeExcludeSubtree value
"{}"'.format(args.value))
-
-def remove_excludescope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- try:
- plugin.remove_excludescope(args.value)
- except ldap.NO_SUCH_ATTRIBUTE:
- log.error('Error: Failed to delete. No value "{0}"
found.'.format(args.value))
- else:
- log.info('successfully removed memberOfEntryScopeExcludeSubtree value
"{}"'.format(args.value))
-
-def remove_all_excludescope(inst, basedn, log, args):
- plugin = MemberOfPlugin(inst)
- plugin.remove_all_excludescope()
- log.info('successfully removed all memberOfEntryScopeExcludeSubtree values')
def fixup(inst, basedn, log, args):
plugin = MemberOfPlugin(inst)
log.info('Attempting to add task entry... This will fail if MemberOf plug-in is
not enabled.')
- fixup_task = plugin.fixup(args.basedn, args.filter)
- log.info('Successfully added task entry ' + fixup_task.dn)
+ assert plugin.status(), "'%s' is disabled. Fix up task can't be
executed" % plugin.rdn
+ fixup_task = plugin.fixup(args.DN, args.filter)
+ fixup_task.wait()
+ exitcode = fixup_task.get_exit_code()
+ assert exitcode == 0, 'MemberOf fixup task for %s has failed. Please, check
logs'
+ log.info('Successfully added task entry for %s', args.DN)
+
+
+def _add_parser_args(parser):
+ parser.add_argument('--attr', nargs='+', help='The value to set
as memberOfAttr')
+ parser.add_argument('--groupattr', nargs='+', help='The value to
set as memberOfGroupAttr')
+ parser.add_argument('--allbackends', choices=['on', 'off'],
type=str.lower,
+ help='The value to set as memberOfAllBackends')
+ parser.add_argument('--skipnested', choices=['on', 'off'],
type=str.lower,
+ help='The value to set as memberOfSkipNested')
+ parser.add_argument('--scope', help='The value to set as
memberOfEntryScope')
+ parser.add_argument('--exclude', help='The value to set as
memberOfEntryScopeExcludeSubtree')
+ parser.add_argument('--autoaddoc', type=str.lower, help='The value to set
as memberOfAutoAddOC')
+
def create_parser(subparsers):
memberof_parser = subparsers.add_parser('memberof', help='Manage and
configure MemberOf plugin')
@@ -208,69 +101,32 @@ def create_parser(subparsers):
add_generic_plugin_parsers(subcommands, MemberOfPlugin)
- attr_parser = subcommands.add_parser('attr', help='get or set
memberofattr')
- attr_parser.set_defaults(func=manage_attr)
- attr_parser.add_argument('value', nargs='?', help='The value to
set as memberofattr')
-
- groupattr_parser = subcommands.add_parser('groupattr', help='get or
manage memberofgroupattr')
- groupattr_parser.set_defaults(func=display_groupattr)
- groupattr_subcommands = groupattr_parser.add_subparsers(help='action')
- add_groupattr_parser = groupattr_subcommands.add_parser('add', help='add
memberofgroupattr value')
- add_groupattr_parser.set_defaults(func=add_groupattr)
- add_groupattr_parser.add_argument('value', help='The value to add in
memberofgroupattr')
- del_groupattr_parser = groupattr_subcommands.add_parser('del',
help='remove memberofgroupattr value')
- del_groupattr_parser.set_defaults(func=remove_groupattr)
- del_groupattr_parser.add_argument('value', help='The value to remove from
memberofgroupattr')
-
- allbackends_parser = subcommands.add_parser('allbackends', help='get or
manage memberofallbackends')
- allbackends_parser.set_defaults(func=display_allbackends)
- allbackends_subcommands = allbackends_parser.add_subparsers(help='action')
- on_allbackends_parser = allbackends_subcommands.add_parser('on',
help='enable all backends for memberof')
- on_allbackends_parser.set_defaults(func=enable_allbackends)
- off_allbackends_parser = allbackends_subcommands.add_parser('off',
help='disable all backends for memberof')
- off_allbackends_parser.set_defaults(func=disable_allbackends)
-
- skipnested_parser = subcommands.add_parser('skipnested', help='get or
manage memberofskipnested')
- skipnested_parser.set_defaults(func=display_skipnested)
- skipnested_subcommands = skipnested_parser.add_subparsers(help='action')
- on_skipnested_parser = skipnested_subcommands.add_parser('on', help='skip
nested groups for memberof')
- on_skipnested_parser.set_defaults(func=enable_skipnested)
- off_skipnested_parser = skipnested_subcommands.add_parser('off',
help="don't skip nested groups for memberof")
- off_skipnested_parser.set_defaults(func=disable_skipnested)
-
- autoaddoc_parser = subcommands.add_parser('autoaddoc', help='get or set
memberofautoaddoc')
- autoaddoc_parser.set_defaults(func=manage_autoaddoc)
- autoaddoc_parser.add_argument('value', nargs='?',
choices=['nsmemberof', 'inetuser', 'inetadmin', 'del'],
- type=str.lower, help='The value to set as
memberofautoaddoc or del to remove the attribute')
-
- scope_parser = subcommands.add_parser('scope', help='get or manage
memberofentryscope')
- scope_parser.set_defaults(func=display_scope)
- scope_subcommands = scope_parser.add_subparsers(help='action')
- add_scope_parser = scope_subcommands.add_parser('add', help='add
memberofentryscope value')
- add_scope_parser.set_defaults(func=add_scope)
- add_scope_parser.add_argument('value', help='The value to add in
memberofentryscope')
- del_scope_parser = scope_subcommands.add_parser('del', help='remove
memberofentryscope value')
- del_scope_parser.set_defaults(func=remove_scope)
- del_scope_parser.add_argument('value', help='The value to remove from
memberofentryscope')
- delall_scope_parser = scope_subcommands.add_parser('delall', help='remove
all memberofentryscope values')
- delall_scope_parser.set_defaults(func=remove_all_scope)
-
- exclude_parser = subcommands.add_parser('exclude', help='get or manage
memberofentryscopeexcludesubtree')
- exclude_parser.set_defaults(func=display_excludescope)
- exclude_subcommands = exclude_parser.add_subparsers(help='action')
- add_exclude_parser = exclude_subcommands.add_parser('add', help='add
memberofentryscopeexcludesubtree value')
- add_exclude_parser.set_defaults(func=add_excludescope)
- add_exclude_parser.add_argument('value', help='The value to add in
memberofentryscopeexcludesubtree')
- del_exclude_parser = exclude_subcommands.add_parser('del', help='remove
memberofentryscopeexcludesubtree value')
- del_exclude_parser.set_defaults(func=remove_excludescope)
- del_exclude_parser.add_argument('value', help='The value to remove from
memberofentryscopeexcludesubtree')
- delall_exclude_parser = exclude_subcommands.add_parser('delall',
help='remove all memberofentryscopeexcludesubtree values')
- delall_exclude_parser.set_defaults(func=remove_all_excludescope)
-
- fixup_parser = subcommands.add_parser('fixup', help='run the fix-up task
for memberof plugin')
+ edit_parser = subcommands.add_parser('edit', help='Edit the plugin')
+ edit_parser.set_defaults(func=memberof_edit)
+ _add_parser_args(edit_parser)
+ edit_parser.add_argument('--config-entry', help='The value to set as
nsslapd-pluginConfigArea')
+
+ config_parser = subcommands.add_parser('config-entry', help='Manage the
config entry')
+ config_subcommands = config_parser.add_subparsers(help='action')
+ add_config_parser = config_subcommands.add_parser('add', help='Add the
config entry')
+ add_config_parser.set_defaults(func=memberof_add_config)
+ add_config_parser.add_argument('DN', help='The config entry full
DN')
+ _add_parser_args(add_config_parser)
+ edit_config_parser = config_subcommands.add_parser('edit', help='Edit the
config entry')
+ edit_config_parser.set_defaults(func=memberof_edit_config)
+ edit_config_parser.add_argument('DN', help='The config entry full
DN')
+ _add_parser_args(edit_config_parser)
+ show_config_parser = config_subcommands.add_parser('show', help='Display
the config entry')
+ show_config_parser.set_defaults(func=memberof_show_config)
+ show_config_parser.add_argument('DN', help='The config entry full
DN')
+ del_config_parser = config_subcommands.add_parser('delete', help='Delete
the config entry')
+ del_config_parser.set_defaults(func=memberof_del_config)
+ del_config_parser.add_argument('DN', help='The config entry full
DN')
+
+ fixup_parser = subcommands.add_parser('fixup', help='Run the fix-up task
for memberOf plugin')
fixup_parser.set_defaults(func=fixup)
- fixup_parser.add_argument('-b', '--basedn', required=True,
help="base DN that contains entries to fix up")
- fixup_parser.add_argument('-f', '--filter', help="Filter for
entries to fix up.\n"
- "If omitted, all entries with objectclass inetuser/inetadmin/nsmemberof
under the\n"
- "specified base will have their memberOf attribute regenerated."
- )
+ fixup_parser.add_argument('DN', help="base DN that contains entries to
fix up")
+ fixup_parser.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/cli_ctl/instance.py
b/src/lib389/lib389/cli_ctl/instance.py
index ae17307..b70ec7c 100644
--- a/src/lib389/lib389/cli_ctl/instance.py
+++ b/src/lib389/lib389/cli_ctl/instance.py
@@ -68,7 +68,7 @@ def instance_create(inst, log, args):
sd = SetupDs(args.verbose, args.dryrun, log, args.containerised)
if sd.create_from_inf(args.file):
- # print("Sucessfully created instance")
+ # print("Successfully created instance")
return True
else:
# print("Failed to create instance")
@@ -200,6 +200,3 @@ def create_parser(subcommands):
remove_parser.set_defaults(func=instance_remove)
remove_parser.add_argument('--do-it', dest="ack", help="By
default we do a dry run. This actually initiates the removal of the instance.",
action='store_true', default=False)
-
-
-
diff --git a/src/lib389/lib389/cli_idm/__init__.py
b/src/lib389/lib389/cli_idm/__init__.py
index cb4fd11..fcf0175 100644
--- a/src/lib389/lib389/cli_idm/__init__.py
+++ b/src/lib389/lib389/cli_idm/__init__.py
@@ -107,13 +107,13 @@ def _generic_create(inst, basedn, log, manager_class, kwargs,
args=None):
mc = manager_class(inst, basedn)
o = mc.create(properties=kwargs)
o_str = o.__unicode__()
- log.info('Sucessfully created %s' % o_str)
+ log.info('Successfully created %s' % o_str)
def _generic_delete(inst, basedn, log, object_class, dn, args=None):
# Load the oc direct
o = object_class(inst, dn)
o.delete()
- log.info('Sucessfully deleted %s' % dn)
+ log.info('Successfully deleted %s' % dn)
# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
diff --git a/src/lib389/lib389/clitools/ds_setup b/src/lib389/lib389/clitools/ds_setup
index 212a34a..9e8b0d0 100755
--- a/src/lib389/lib389/clitools/ds_setup
+++ b/src/lib389/lib389/clitools/ds_setup
@@ -66,7 +66,7 @@ By setting this value you acknowledge and take responsibility for the
fact this
print('Launching ...')
sd = SetupDs(args.verbose, args.dryrun)
if sd.create_from_inf(args.file):
- print("Sucessfully created instance")
+ print("Successfully created instance")
else:
print("Failed to create instance")
sys.exit(1)
@@ -75,4 +75,3 @@ By setting this value you acknowledge and take responsibility for the
fact this
if __name__ == '__main__':
ds_setup_main()
-
diff --git a/src/lib389/lib389/replica.py b/src/lib389/lib389/replica.py
index cc695c7..a462c98 100644
--- a/src/lib389/lib389/replica.py
+++ b/src/lib389/lib389/replica.py
@@ -1073,15 +1073,15 @@ class Replica(DSLdapObject):
raise ValueError('Failed to update replica: ' + str(e))
elif replicarole == ReplicaRole.CONSUMER and newrole == ReplicaRole.MASTER:
try:
- self.apply_mods([(REPL_TYPE, str(REPLICA_RDWR_TYPE)),
- (REPL_FLAGS, str(REPLICA_FLAGS_WRITE)),
- (REPL_ID, str(rid))])
+ self.replace_many([(REPL_TYPE, str(REPLICA_RDWR_TYPE)),
+ (REPL_FLAGS, str(REPLICA_FLAGS_WRITE)),
+ (REPL_ID, str(rid))])
except ldap.LDAPError as e:
raise ValueError('Failed to update replica: ' + str(e))
elif replicarole == ReplicaRole.HUB and newrole == ReplicaRole.MASTER:
try:
- self.apply_mods([(REPL_TYPE, str(REPLICA_RDWR_TYPE)),
- (REPL_ID, str(rid))])
+ self.replace_many([(REPL_TYPE, str(REPLICA_RDWR_TYPE)),
+ (REPL_ID, str(rid))])
except ldap.LDAPError as e:
raise ValueError('Failed to update replica: ' + str(e))
@@ -1103,15 +1103,15 @@ class Replica(DSLdapObject):
# Demote it - set the replica type, flags and rid
if replicarole == ReplicaRole.MASTER and newrole == ReplicaRole.HUB:
try:
- self.apply_mods([(REPL_TYPE, str(REPLICA_RDONLY_TYPE)),
- (REPL_ID, str(CONSUMER_REPLICAID))])
+ self.replace_many([(REPL_TYPE, str(REPLICA_RDONLY_TYPE)),
+ (REPL_ID, str(CONSUMER_REPLICAID))])
except ldap.LDAPError as e:
raise ValueError('Failed to update replica: ' + str(e))
elif replicarole == ReplicaRole.MASTER and newrole == ReplicaRole.CONSUMER:
try:
- self.apply_mods([(REPL_TYPE, str(REPLICA_RDONLY_TYPE)),
- (REPL_FLAGS, str(REPLICA_FLAGS_RDONLY)),
- (REPL_ID, str(CONSUMER_REPLICAID))])
+ self.replace_many([(REPL_TYPE, str(REPLICA_RDONLY_TYPE)),
+ (REPL_FLAGS, str(REPLICA_FLAGS_RDONLY)),
+ (REPL_ID, str(CONSUMER_REPLICAID))])
except ldap.LDAPError as e:
raise ValueError('Failed to update replica: ' + str(e))
elif replicarole == ReplicaRole.HUB and newrole == ReplicaRole.CONSUMER:
diff --git a/src/lib389/lib389/tests/cli/conf_backend_test.py
b/src/lib389/lib389/tests/cli/conf_backend_test.py
index 5043622..351d2bf 100644
--- a/src/lib389/lib389/tests/cli/conf_backend_test.py
+++ b/src/lib389/lib389/tests/cli/conf_backend_test.py
@@ -53,7 +53,7 @@ def create_backend(topology_st, request):
args.suffix = SUFFIX
backend_create(topology_st.standalone, None, None, args)
- check_output("The database was sucessfully created")
+ check_output("The database was successfully created")
def fin():
sys.stdout = io.StringIO()
@@ -66,7 +66,7 @@ def create_backend(topology_st, request):
# Delete backend
backend_delete(topology_st.standalone, None, None, args, warn=False)
- check_output("sucessfully deleted")
+ check_output("successfully deleted")
# Verify it's removed
args.suffix = False
@@ -137,7 +137,7 @@ def test_backend_cli(topology_st, create_backend):
args.suffix = SUB_SUFFIX
args.be_name = SUB_BE_NAME
backend_create(topology_st.standalone, None, topology_st.logcap.log, args)
- check_output("The database was sucessfully created")
+ check_output("The database was successfully created")
# Verify subsuffix
args.suffix = False
@@ -155,7 +155,7 @@ def test_backend_cli(topology_st, create_backend):
args.enable_readonly = True # Setting nsslapd-readonly to "on"
args.disable_readonly = False
backend_set(topology_st.standalone, None, topology_st.logcap.log, args)
- check_output("sucessfully updated")
+ check_output("successfully updated")
# Verify modified worked
args.selector = SUB_BE_NAME
@@ -165,7 +165,7 @@ def test_backend_cli(topology_st, create_backend):
# Delete subsuffix
args.suffix = SUB_SUFFIX
backend_delete(topology_st.standalone, None, topology_st.logcap.log, args,
warn=False)
- check_output("sucessfully deleted")
+ check_output("successfully deleted")
# Verify it is deleted
args.suffix = False
@@ -175,7 +175,7 @@ def test_backend_cli(topology_st, create_backend):
# Modify backend (use same args from subsuffix modify)
args.be_name = BE_NAME
backend_set(topology_st.standalone, None, topology_st.logcap.log, args)
- check_output("sucessfully updated")
+ check_output("successfully updated")
# Verify modified worked
args.selector = BE_NAME
diff --git a/src/lib389/lib389/tests/cli/conf_chaining_test.py
b/src/lib389/lib389/tests/cli/conf_chaining_test.py
index be19077..0b44770 100644
--- a/src/lib389/lib389/tests/cli/conf_chaining_test.py
+++ b/src/lib389/lib389/tests/cli/conf_chaining_test.py
@@ -46,7 +46,7 @@ def create_backend(topology_st, request):
args.create_entries = True
args.suffix = SUFFIX
backend_create(topology_st.standalone, None, None, args)
- check_output("The database was sucessfully created")
+ check_output("The database was successfully created")
def fin():
sys.stdout = io.StringIO()
@@ -60,7 +60,7 @@ def create_backend(topology_st, request):
# Delete backend
backend_delete(topology_st.standalone, None, None, args, warn=False)
- check_output("sucessfully deleted")
+ check_output("successfully deleted")
# Verify it's removed
args.suffix = False
diff --git a/src/lib389/lib389/tests/cli/idm_group_test.py
b/src/lib389/lib389/tests/cli/idm_group_test.py
index 51ad85e..a9bf921 100644
--- a/src/lib389/lib389/tests/cli/idm_group_test.py
+++ b/src/lib389/lib389/tests/cli/idm_group_test.py
@@ -35,7 +35,7 @@ def test_group_tasks(topology):
topology.logcap.flush()
g_args.cn = 'testgroup'
create(topology.standalone, DEFAULT_SUFFIX, topology.logcap.log, g_args)
- assert(topology.logcap.contains("Sucessfully created testgroup"))
+ assert(topology.logcap.contains("Successfully created testgroup"))
# Assert it exists
topology.logcap.flush()
@@ -54,7 +54,7 @@ def test_group_tasks(topology):
u_args.uidNumber = '5000'
u_args.gidNumber = '5000'
create_user(topology.standalone, DEFAULT_SUFFIX, topology.logcap.log, u_args)
- assert(topology.logcap.contains("Sucessfully created testuser"))
+ assert(topology.logcap.contains("Successfully created testuser"))
# Add them to the group as a member
topology.logcap.flush()
@@ -86,5 +86,4 @@ def test_group_tasks(topology):
topology.logcap.flush()
g_args.dn = "cn=testgroup,ou=groups,dc=example,dc=com"
delete(topology.standalone, DEFAULT_SUFFIX, topology.logcap.log, g_args, warn=False)
- assert(topology.logcap.contains("Sucessfully deleted
cn=testgroup,ou=groups,dc=example,dc=com"))
-
+ assert(topology.logcap.contains("Successfully deleted
cn=testgroup,ou=groups,dc=example,dc=com"))
diff --git a/src/lib389/lib389/tests/cli/idm_user_test.py
b/src/lib389/lib389/tests/cli/idm_user_test.py
index 42abd02..fdbc17d 100644
--- a/src/lib389/lib389/tests/cli/idm_user_test.py
+++ b/src/lib389/lib389/tests/cli/idm_user_test.py
@@ -52,7 +52,7 @@ def test_user_tasks(topology):
u_args.gidNumber = '5000'
create(topology.standalone, DEFAULT_SUFFIX, topology.logcap.log, u_args)
- assert(topology.logcap.contains("Sucessfully created testuser"))
+ assert(topology.logcap.contains("Successfully created testuser"))
# Assert they exist
topology.logcap.flush()
get(topology.standalone, DEFAULT_SUFFIX, topology.logcap.log, u_args)
@@ -82,9 +82,8 @@ def test_user_tasks(topology):
# Enroll a dummy sshkey
- # Delete it
+ # Delete it
topology.logcap.flush()
u_args.dn = 'uid=testuser,ou=people,dc=example,dc=com'
delete(topology.standalone, DEFAULT_SUFFIX, topology.logcap.log, u_args, warn=False)
- assert(topology.logcap.contains('Sucessfully deleted
uid=testuser,ou=people,dc=example,dc=com'))
-
+ assert(topology.logcap.contains('Successfully deleted
uid=testuser,ou=people,dc=example,dc=com'))
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.