summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--API.txt113
-rw-r--r--install/share/Makefile.am2
-rw-r--r--install/share/automember.ldif32
-rw-r--r--install/share/replica-automember.ldif8
-rw-r--r--ipalib/constants.py1
-rw-r--r--ipalib/plugins/automember.py587
-rw-r--r--ipalib/plugins/user.py3
-rw-r--r--ipaserver/install/dsinstance.py9
-rw-r--r--tests/test_xmlrpc/objectclasses.py5
-rw-r--r--tests/test_xmlrpc/test_automember_plugin.py1074
10 files changed, 1834 insertions, 0 deletions
diff --git a/API.txt b/API.txt
index b7578b6..d61e7e1 100644
--- a/API.txt
+++ b/API.txt
@@ -99,6 +99,119 @@ option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+command: automember_add
+args: 1,5,3
+arg: Str('cn', cli_name='automember_rule', label=Gettext('Automember Rule', domain='ipa', localedir=None), normalizer=<lambda>)
+option: Str('description', attribute=True, cli_name='desc', label=Gettext('Description', domain='ipa', localedir=None), multivalue=False, required=False)
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+command: automember_add_condition
+args: 1,8,5
+arg: Str('cn', cli_name='automember_rule', label=Gettext('Automember Rule', domain='ipa', localedir=None), normalizer=<lambda>)
+option: Str('description', attribute=True, autofill=False, cli_name='desc', label=Gettext('Description', domain='ipa', localedir=None), multivalue=False, required=False)
+option: List('automemberinclusiveregex?', alwaysask=True, cli_name='inclusive_regex', label=Gettext('Inclusive Regex', domain='ipa', localedir=None), multivalue=True)
+option: List('automemberexclusiveregex?', alwaysask=True, cli_name='exclusive_regex', label=Gettext('Exclusive Regex', domain='ipa', localedir=None), multivalue=True)
+option: Str('key', flags=['no_create', 'no_update', 'no_search'], label=Gettext('Attribute Key', domain='ipa', localedir=None))
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+output: Output('failed', <type 'dict'>, Gettext('Conditions that could not be added', domain='ipa', localedir=None))
+output: Output('completed', <type 'int'>, Gettext('Number of conditions added', domain='ipa', localedir=None))
+command: automember_default_group_remove
+args: 0,5,3
+option: Str('description', attribute=True, autofill=False, cli_name='desc', label=Gettext('Description', domain='ipa', localedir=None), multivalue=False, required=False)
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+command: automember_default_group_set
+args: 0,6,3
+option: Str('description', attribute=True, autofill=False, cli_name='desc', label=Gettext('Description', domain='ipa', localedir=None), multivalue=False, required=False)
+option: Str('automemberdefaultgroup', cli_name='default_group', flags=['no_create', 'no_update'], label=Gettext('Default Group', domain='ipa', localedir=None))
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+command: automember_default_group_show
+args: 0,4,3
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+command: automember_del
+args: 1,1,3
+arg: Str('cn', cli_name='automember_rule', label=Gettext('Automember Rule', domain='ipa', localedir=None), normalizer=<lambda>)
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Output('result', <type 'dict'>, 'list of deletions that failed')
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+command: automember_find
+args: 1,5,4
+arg: Str('criteria?', noextrawhitespace=False)
+option: Str('description', attribute=True, autofill=False, cli_name='desc', label=Gettext('Description', domain='ipa', localedir=None), multivalue=False, query=True, required=False)
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: ListOfEntries('result', (<type 'list'>, <type 'tuple'>), Gettext('A list of LDAP entries', domain='ipa', localedir=None))
+output: Output('count', <type 'int'>, 'Number of entries returned')
+output: Output('truncated', <type 'bool'>, 'True if not all results were returned')
+command: automember_mod
+args: 1,5,3
+arg: Str('cn', cli_name='automember_rule', label=Gettext('Automember Rule', domain='ipa', localedir=None), normalizer=<lambda>)
+option: Str('description', attribute=True, autofill=False, cli_name='desc', label=Gettext('Description', domain='ipa', localedir=None), multivalue=False, required=False)
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+command: automember_remove_condition
+args: 1,8,5
+arg: Str('cn', cli_name='automember_rule', label=Gettext('Automember Rule', domain='ipa', localedir=None), normalizer=<lambda>)
+option: Str('description', attribute=True, autofill=False, cli_name='desc', label=Gettext('Description', domain='ipa', localedir=None), multivalue=False, required=False)
+option: List('automemberinclusiveregex?', alwaysask=True, cli_name='inclusive_regex', label=Gettext('Inclusive Regex', domain='ipa', localedir=None), multivalue=True)
+option: List('automemberexclusiveregex?', alwaysask=True, cli_name='exclusive_regex', label=Gettext('Exclusive Regex', domain='ipa', localedir=None), multivalue=True)
+option: Str('key', flags=['no_create', 'no_update', 'no_search'], label=Gettext('Attribute Key', domain='ipa', localedir=None))
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
+output: Output('failed', <type 'dict'>, Gettext('Conditions that could not be removed', domain='ipa', localedir=None))
+output: Output('completed', <type 'int'>, Gettext('Number of conditions removed', domain='ipa', localedir=None))
+command: automember_show
+args: 1,4,3
+arg: Str('cn', cli_name='automember_rule', label=Gettext('Automember Rule', domain='ipa', localedir=None), normalizer=<lambda>)
+option: StrEnum('type', label=Gettext('Grouping Type', domain='ipa', localedir=None), values=(u'group', u'hostgroup'))
+option: Flag('all', autofill=True, cli_name='all', default=False, exclude='webui', flags=['no_output'])
+option: Flag('raw', autofill=True, cli_name='raw', default=False, exclude='webui', flags=['no_output'])
+option: Str('version?', exclude='webui', flags=['no_option', 'no_output'])
+output: Output('summary', (<type 'unicode'>, <type 'NoneType'>), 'User-friendly description of action performed')
+output: Entry('result', <type 'dict'>, Gettext('A dictionary representing an LDAP entry', domain='ipa', localedir=None))
+output: Output('value', <type 'unicode'>, "The primary_key value of the entry, e.g. 'jdoe' for a user")
command: automountkey_add
args: 2,7,3
arg: Str('automountlocationcn', cli_name='automountlocation', label=Gettext('Location', domain='ipa', localedir=None), query=True, required=True)
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index c636109..51b9ad2 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -49,6 +49,8 @@ app_DATA = \
entryusn.ldif \
root-autobind.ldif \
sudobind.ldif \
+ automember.ldif \
+ replica-automember.ldif \
$(NULL)
EXTRA_DIST = \
diff --git a/install/share/automember.ldif b/install/share/automember.ldif
new file mode 100644
index 0000000..1520e62
--- /dev/null
+++ b/install/share/automember.ldif
@@ -0,0 +1,32 @@
+# Configuration for Auto Membership Plugin for Master
+# installation. This method should be revisted for
+# optimization due to a bug within 389 DS which prevents
+# the definition files from being added seperatly after
+# the insertion of cn=Auto Membership Plugin,cn=plugins,cn=config
+# and subsequent 389 DS restart.
+dn: cn=Auto Membership Plugin,cn=plugins,cn=config
+changetype: modify
+add: nsslapd-pluginConfigArea
+nsslapd-pluginConfigArea: cn=automember,cn=etc,$SUFFIX
+
+dn: cn=automember,cn=etc,$SUFFIX
+changetype: add
+objectClass: top
+objectClass: nsContainer
+cn: automember
+
+dn: cn=Hostgroup,cn=automember,cn=etc,$SUFFIX
+changetype: add
+objectclass: autoMemberDefinition
+cn: Hostgroup
+autoMemberScope: cn=computers,cn=accounts,$SUFFIX
+autoMemberFilter: objectclass=ipaHost
+autoMemberGroupingAttr: member:dn
+
+dn: cn=Group,cn=automember,cn=etc,$SUFFIX
+changetype: add
+objectclass: autoMemberDefinition
+cn: Group
+autoMemberScope: cn=users,cn=accounts,$SUFFIX
+autoMemberFilter: objectclass=posixAccount
+autoMemberGroupingAttr: member:dn
diff --git a/install/share/replica-automember.ldif b/install/share/replica-automember.ldif
new file mode 100644
index 0000000..15d5d10
--- /dev/null
+++ b/install/share/replica-automember.ldif
@@ -0,0 +1,8 @@
+# Configuration for Auto Membership Plugin for Replica
+# installation. This method should be revisted for
+# optimization due to a bug within 389 DS.
+# dsinstance.py should eventually insert this during common_setup.
+dn: cn=Auto Membership Plugin,cn=plugins,cn=config
+changetype: modify
+add: nsslapd-pluginConfigArea
+nsslapd-pluginConfigArea: cn=automember,cn=etc,$SUFFIX
diff --git a/ipalib/constants.py b/ipalib/constants.py
index 51cf566..b4bb86d 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -112,6 +112,7 @@ DEFAULT_CONFIG = (
('container_sudocmd', 'cn=sudocmds,cn=sudo'),
('container_sudocmdgroup', 'cn=sudocmdgroups,cn=sudo'),
('container_entitlements', 'cn=entitlements,cn=etc'),
+ ('container_automember', 'cn=automember,cn=etc'),
# Ports, hosts, and URIs:
# FIXME: let's renamed xmlrpc_uri to rpc_xml_uri
diff --git a/ipalib/plugins/automember.py b/ipalib/plugins/automember.py
new file mode 100644
index 0000000..db58a7a
--- /dev/null
+++ b/ipalib/plugins/automember.py
@@ -0,0 +1,587 @@
+# Authors:
+# Jr Aquino <jr.aquino@citrix.com>
+#
+# Copyright (C) 2011 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from ipalib import api, errors
+from ipalib import Str, StrEnum
+from ipalib.plugins.baseldap import *
+from ipalib import _, ngettext
+from ipalib.request import context
+from ipalib.dn import *
+import ldap as _ldap
+
+__doc__ = _("""
+Auto Membership Rule.
+
+Bring clarity to the membership of hosts and users by configuring inclusive
+or exclusive regex paterns, you can automatically assign a new entries into
+a group or hostgroup based upon attribute information.
+
+A rule is directly associated with a group by name, so you cannot create
+a rule without an accompanying group or hostgroup
+
+A condition is a regular expression used by 389-ds to match a new incoming
+entry with an automember rule. If it matches an inclusive rule then the
+entry is added to the appropriate group or hostgroup.
+
+EXAMPLES:
+
+ Create the initial group or hostgroup:
+ ipa hostgroup-add --desc="Web Servers" webservers
+ ipa group-add --desc="Developers" devel
+
+ Create the initial rule:
+ ipa automember-add --type=hostgroup webservers
+ ipa automember-add --type=group devel
+
+ Add a condition to the rule:
+ ipa automember-add-condition --key=fqdn --type=hostgroup --inclusive-regex=^web[1-9]+\.example\.com webservers
+ ipa automember-add-condition --key=manager --type=group --inclusive-regex=^uid=mscott devel
+
+ Add an exclusive condition to the rule to prevent auto assignment:
+ ipa automember-add-condition --key=fqdn --type=hostgroup --exclusive-regex=^web5\.example\.com webservers
+
+ Add a host:
+ ipa host-add web1.example.com
+
+ Add a user:
+ ipa user-add --first=Tim --last=User --password tuser1 --manager=mscott
+
+ Verify automembership:
+ ipa hostgroup-show webservers
+ Host-group: webservers
+ Description: Web Servers
+ Member hosts: web1.example.com
+
+ ipa group-show devel
+ Group name: devel
+ Description: Developers
+ GID: 1004200000
+ Member users: tuser
+
+ Remove a condition from the rule:
+ ipa automember-remove-condition --key=fqdn --type=hostgroup --inclusive-regex=^web[1-9]+\.example\.com webservers
+
+ Modify the automember rule:
+ ipa automember-mod
+
+ Set the default target group:
+ ipa automember-default-group-set --default-group=webservers --type=hostgroup
+ ipa automember-default-group-set --default-group=ipausers --type=group
+
+ Set the default target group:
+ ipa automember-default-group-remove --type=hostgroup
+ ipa automember-default-group-remove --type=group
+
+ Show the default target group:
+ ipa automember-default-group-show --type=hostgroup
+ ipa automember-default-group-show --type=group
+
+ Find all of the automember rules:
+ ipa automember-find
+
+ Display a automember rule:
+ ipa automember-show --type=hostgroup webservers
+ ipa automember-show --type=group devel
+
+ Delete an automember rule:
+ ipa automember-del --type=hostgroup webservers
+ ipa automember-del --type=group devel
+""")
+
+# Options used by Condition Add and Remove.
+INCLUDE_RE = 'automemberinclusiveregex'
+EXCLUDE_RE = 'automemberexclusiveregex'
+
+regex_attrs = (
+ List('automemberinclusiveregex?',
+ cli_name='inclusive_regex',
+ label=_('Inclusive Regex'),
+ doc=_('Inclusive Regex'),
+ multivalue=True,
+ alwaysask=True,
+ ),
+ List('automemberexclusiveregex?',
+ cli_name='exclusive_regex',
+ label=_('Exclusive Regex'),
+ doc=_('Exclusive Regex'),
+ multivalue=True,
+ alwaysask=True,
+ ),
+ Str('key',
+ label=_('Attribute Key'),
+ doc=_('Attribute to filter via regex. For example fqdn for a host, or manager for a user'),
+ flags=['no_create', 'no_update', 'no_search']
+ ),
+)
+
+group_type = (
+ StrEnum('type',
+ label=_('Grouping Type'),
+ doc=_('Grouping to which the rule applies'),
+ values=(u'group', u'hostgroup', ),
+ ),
+)
+
+automember_rule = (
+ Str('cn',
+ cli_name='automember_rule',
+ label=_('Automember Rule'),
+ doc=_('Automember Rule'),
+ normalizer=lambda value: value.lower(),
+ ),
+)
+
+class automember(LDAPObject):
+
+ """
+ Bring automember to a hostgroup with an Auto Membership Rule.
+ """
+
+ container_dn = api.env.container_automember
+
+ object_name = 'auto_member_rule'
+ object_name_plural = 'auto_member_rules'
+ object_class = ['top', 'automemberregexrule']
+ default_attributes = [
+ 'automemberinclusiveregex', 'automemberexclusiveregex',
+ 'cn', 'automembertargetgroup', 'description', 'automemberdefaultgroup'
+ ]
+
+ label = _('Auto Membership Rule')
+
+ takes_params = (
+ Str('description?',
+ cli_name='desc',
+ label=_('Description'),
+ doc=_('A description of this auto member rule'),
+ ),
+ Str('automemberdefaultgroup?',
+ cli_name='default_group',
+ label=_('Default Group'),
+ doc=_('Default group for entires to land'),
+ flags=['no_create', 'no_update', 'no_search']
+ ),
+ )
+
+ def dn_exists(self, grouptype, groupname, *keys):
+ ldap = self.api.Backend.ldap2
+ dn = self.api.Object[grouptype].get_dn(groupname)
+ try:
+ (gdn, entry_attrs) = ldap.get_entry(dn, [])
+ except errors.NotFound:
+ raise errors.NotFound(reason=_(u'Group: %s not found!' % groupname))
+ return gdn
+
+ def get_dn(self, *keys, **options):
+ if self.parent_object:
+ parent_dn = self.api.Object[self.parent_object].get_dn(*keys[:-1])
+ else:
+ parent_dn = self.container_dn
+ grouptype = options['type']
+ try:
+ ndn = DN(('cn', keys[-1]), ('cn', grouptype), DN(parent_dn))
+ except IndexError:
+ ndn = DN(('cn', grouptype), DN(parent_dn))
+ parent_dn = str(ndn)
+ return parent_dn
+
+ def check_attr(self, attr):
+ """
+ Verify that the user supplied key is a valid attribute in the schema
+ """
+ ldap = self.api.Backend.ldap2
+ if not ldap.schema:
+ ldap.get_schema()
+ obj = ldap.schema.get_obj(_ldap.schema.AttributeType, attr)
+ if obj is not None:
+ return obj
+ else:
+ raise errors.NotFound(reason=_('%s is not a valid attribute.' % attr))
+
+api.register(automember)
+
+
+def automember_container_exists(ldap):
+ try:
+ ldap.get_entry(api.env.container_automember, [])
+ except errors.NotFound:
+ return False
+ return True
+
+class automember_add(LDAPCreate):
+ __doc__ = _("""
+ Add an automember rule.
+ """)
+ takes_options = group_type
+ takes_args = automember_rule
+ msg_summary = _('Added automember rule "%(value)s"')
+
+ def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+
+ entry_attrs['cn'] = keys[-1]
+ if not automember_container_exists(self.api.Backend.ldap2):
+ raise errors.NotFound(reason=_('Auto Membership is not configured'))
+ entry_attrs['automembertargetgroup'] = self.obj.dn_exists(options['type'], keys[-1])
+ return dn
+
+ def execute(self, *keys, **options):
+ result = super(automember_add, self).execute(*keys, **options)
+ result['value'] = keys[-1]
+ return result
+
+api.register(automember_add)
+
+
+class automember_add_condition(LDAPUpdate):
+ __doc__ = _("""
+ Add conditions to an automember rule.
+ """)
+ has_output_params = (
+ Str('failed',
+ label=_('Failed to add'),
+ flags=['suppress_empty'],
+ ),
+ )
+
+ takes_options = regex_attrs + group_type
+ takes_args = automember_rule
+ msg_summary = _('Added condition(s) to "%(value)s"')
+
+ # Prepare the output to expect failed results
+ has_output = (
+ output.summary,
+ output.Entry('result'),
+ output.value,
+ output.Output('failed',
+ type=dict,
+ doc=_('Conditions that could not be added'),
+ ),
+ output.Output('completed',
+ type=int,
+ doc=_('Number of conditions added'),
+ ),
+ )
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ # Check to see if the automember rule exists
+ try:
+ (tdn, test_attrs) = ldap.get_entry(dn, [])
+ except errors.NotFound:
+ raise errors.NotFound(reason=_(u'Auto member rule: %s not found!' % keys[0]))
+ # Define container key
+ key = options['key']
+ # Check to see if the attribute is valid
+ self.obj.check_attr(key)
+
+ key = '%s=' % key
+ completed = 0
+ failed = {'failed': {}}
+
+ for attr in (INCLUDE_RE, EXCLUDE_RE):
+ failed['failed'][attr] = []
+ if attr in options and options[attr]:
+ entry_attrs[attr] = [key + condition for condition in options[attr]]
+ completed += len(entry_attrs[attr])
+ try:
+ (dn, old_entry) = ldap.get_entry(
+ dn, [attr], normalize=self.obj.normalize_dn)
+ for regex in old_entry:
+ if not isinstance(entry_attrs[regex], (list, tuple)):
+ entry_attrs[regex] = [entry_attrs[regex]]
+ duplicate = set(old_entry[regex]) & set(entry_attrs[regex])
+ if len(duplicate) > 0:
+ completed -= 1
+ else:
+ entry_attrs[regex] = list(entry_attrs[regex]) + old_entry[regex]
+ except errors.NotFound:
+ failed['failed'][attr].append(regex)
+
+ # Set failed and completed to they can be harvested in the execute super
+ setattr(context, 'failed', failed)
+ setattr(context, 'completed', completed)
+ setattr(context, 'entry_attrs', entry_attrs)
+
+ # Make sure to returned the failed results if there is nothing to remove
+ if completed == 0:
+ (dn, entry_attrs) = ldap.get_entry(
+ dn, attrs_list, normalize=self.obj.normalize_dn
+ )
+ raise errors.EmptyModlist
+ return dn
+
+ def execute(self, *keys, **options):
+ __doc__ = _("""
+ Override this so we can add completed and failed to the return result.
+ """)
+ try:
+ result = super(automember_add_condition, self).execute(*keys, **options)
+ except errors.EmptyModlist:
+ result = {'result': getattr(context, 'entry_attrs'), 'value': keys[-1]}
+ result['failed'] = getattr(context, 'failed')
+ result['completed'] = getattr(context, 'completed')
+ result['value'] = keys[-1]
+ return result
+
+api.register(automember_add_condition)
+
+
+class automember_remove_condition(LDAPUpdate):
+ __doc__ = _("""
+ Remove conditions from an automember rule.
+ """)
+ takes_options = regex_attrs + group_type
+ takes_args = automember_rule
+ msg_summary = _('Removed condition(s) to "%(value)s"')
+
+ # Prepare the output to expect failed results
+ has_output = (
+ output.summary,
+ output.Entry('result'),
+ output.value,
+ output.Output('failed',
+ type=dict,
+ doc=_('Conditions that could not be removed'),
+ ),
+ output.Output('completed',
+ type=int,
+ doc=_('Number of conditions removed'),
+ ),
+ )
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ # Check to see if the automember rule exists
+ try:
+ (tdn, test_attrs) = ldap.get_entry(dn, [])
+ except errors.NotFound:
+ raise errors.NotFound(reason=_(u'Auto member rule: %s not found!' % keys[0]))
+
+ # Define container key
+ type_attr_default = {'group': 'manager', 'hostgroup': 'fqdn'}
+ if 'key' in options:
+ key = options['key']
+ else:
+ key = type_attr_default[options['type']]
+
+ key = '%s=' % key
+ completed = 0
+ failed = {'failed': {}}
+
+ # Check to see if there are existing exclusive conditions present.
+ (dn, exclude_present) = ldap.get_entry(
+ dn, [EXCLUDE_RE], normalize=self.obj.normalize_dn)
+
+ for attr in (INCLUDE_RE, EXCLUDE_RE):
+ failed['failed'][attr] = []
+ if attr in options and options[attr]:
+ entry_attrs[attr] = [key + condition for condition in options[attr]]
+ (dn, entry_attrs_) = ldap.get_entry(
+ dn, [attr], normalize=self.obj.normalize_dn
+ )
+ old_entry = entry_attrs_.get(attr, [])
+ for regex in entry_attrs[attr]:
+ if regex in old_entry:
+ old_entry.remove(regex)
+ completed += 1
+ else:
+ failed['failed'][attr].append(regex)
+ entry_attrs[attr] = old_entry
+ # Set failed and completed to they can be harvested in the execute super
+ setattr(context, 'failed', failed)
+ setattr(context, 'completed', completed)
+ setattr(context, 'entry_attrs', entry_attrs)
+
+ # Make sure to returned the failed results if there is nothing to remove
+ if completed == 0:
+ (dn, entry_attrs) = ldap.get_entry(
+ dn, attrs_list, normalize=self.obj.normalize_dn
+ )
+ raise errors.EmptyModlist
+ return dn
+
+ def execute(self, *keys, **options):
+ __doc__ = _("""
+ Override this so we can set completed and failed.
+ """)
+ try:
+ result = super(automember_remove_condition, self).execute(*keys, **options)
+ except errors.EmptyModlist:
+ result = {'result': getattr(context, 'entry_attrs'), 'value': keys[-1]}
+ result['failed'] = getattr(context, 'failed')
+ result['completed'] = getattr(context, 'completed')
+ result['value'] = keys[-1]
+ return result
+
+api.register(automember_remove_condition)
+
+
+class automember_mod(LDAPUpdate):
+ __doc__ = _("""
+ Modify an automember rule.
+ """)
+ takes_args = automember_rule
+ takes_options = group_type
+ msg_summary = _('Modified automember rule "%(value)s"')
+
+ def execute(self, *keys, **options):
+ result = super(automember_mod, self).execute(*keys, **options)
+ result['value'] = keys[-1]
+ return result
+
+api.register(automember_mod)
+
+
+class automember_del(LDAPDelete):
+ __doc__ = _("""
+ Delete an automember rule.
+ """)
+ takes_args = automember_rule
+ takes_options = group_type
+ msg_summary = _('Deleted automember rule "%(value)s"')
+
+ def execute(self, *keys, **options):
+ result = super(automember_del, self).execute(*keys, **options)
+ result['value'] = keys[-1]
+ return result
+
+api.register(automember_del)
+
+
+class automember_find(LDAPSearch):
+ __doc__ = _("""
+ Search for automember rules.
+ """)
+ takes_options = group_type
+ has_output_params = LDAPSearch.has_output_params + automember_rule + regex_attrs
+
+ msg_summary = ngettext(
+ '%(count)d rules matched', '%(count)d rules matched', 0
+ )
+
+ def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+ scope = ldap.SCOPE_SUBTREE
+ ndn = DN(('cn', options['type']), DN(base_dn))
+ base_dn = str(ndn)
+ return (filters, base_dn, scope)
+
+api.register(automember_find)
+
+
+class automember_show(LDAPRetrieve):
+ __doc__ = _("""
+ Display information about an automember rule.
+ """)
+ takes_args = automember_rule
+ takes_options = group_type
+ has_output_params = LDAPRetrieve.has_output_params + regex_attrs
+
+ def execute(self, *keys, **options):
+ result = super(automember_show, self).execute(*keys, **options)
+ result['value'] = keys[-1]
+ return result
+
+api.register(automember_show)
+
+
+class automember_default_group_set(LDAPUpdate):
+ __doc__ = _("""
+ Set default group for all unmatched entries.
+ """)
+
+ takes_options = (
+ Str('automemberdefaultgroup',
+ cli_name='default_group',
+ label=_('Default Group'),
+ doc=_('Default group for entires to land'),
+ flags=['no_create', 'no_update']
+ ),
+ ) + group_type
+ msg_summary = _('Set default group for automember "%(value)s"')
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ dn = DN(('cn', options['type']), api.env.container_automember)
+ dn = str(dn)
+ entry_attrs['automemberdefaultgroup'] = self.obj.dn_exists(options['type'], options['automemberdefaultgroup'])
+ return dn
+
+ def execute(self, *keys, **options):
+ result = super(automember_default_group_set, self).execute(*keys, **options)
+ result['value'] = options['type']
+ return result
+
+api.register(automember_default_group_set)
+
+
+class automember_default_group_remove(LDAPUpdate):
+ __doc__ = _("""
+ Remove default group for all unmatched entries.
+ """)
+
+ takes_options = group_type
+ msg_summary = _('Removed default group for automember "%(value)s"')
+
+ def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ dn = DN(('cn', options['type']), api.env.container_automember)
+ dn = str(dn)
+ attr = 'automemberdefaultgroup'
+
+ (dn, entry_attrs_) = ldap.get_entry(
+ dn, [attr], normalize=self.obj.normalize_dn
+ )
+
+ if attr not in entry_attrs_:
+ raise errors.NotFound(reason=_(u'No default group set'))
+ else:
+ entry_attrs[attr] = []
+ return dn
+
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ if 'automemberdefaultgroup' not in entry_attrs:
+ entry_attrs['automemberdefaultgroup'] = u'No default group set'
+ return dn
+
+ def execute(self, *keys, **options):
+ result = super(automember_default_group_remove, self).execute(*keys, **options)
+ result['value'] = options['type']
+ return result
+
+api.register(automember_default_group_remove)
+
+
+class automember_default_group_show(LDAPRetrieve):
+ __doc__ = _("""
+ Display information about the default automember groups.
+ """)
+ takes_options = group_type
+
+ def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
+ dn = DN(('cn', options['type']), api.env.container_automember)
+ dn = str(dn)
+ return dn
+
+ def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ if 'automemberdefaultgroup' not in entry_attrs:
+ entry_attrs['automemberdefaultgroup'] = u'No default group set'
+ return dn
+
+ def execute(self, *keys, **options):
+ result = super(automember_default_group_show, self).execute(*keys, **options)
+ result['value'] = options['type']
+ return result
+
+api.register(automember_default_group_show)
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index d728ad4..92a026d 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -391,6 +391,9 @@ class user_add(LDAPCreate):
def_primary_group = config.get('ipadefaultprimarygroup')
group_dn = self.api.Object['group'].get_dn(def_primary_group)
ldap.add_entry_to_group(dn, group_dn)
+ if self.api.env.wait_for_attr:
+ newentry = wait_for_value(ldap, dn, 'memberOf', def_primary_group)
+ entry_from_entry(entry_attrs, newentry)
self.obj._convert_manager(entry_attrs, **options)
# delete description attribute NO_UPG_MAGIC if present
if options.get('noprivate', False):
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 7ca5db2..09ef8c5 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -250,6 +250,7 @@ class DsInstance(service.Service):
self.step("configuring user private groups", self.__user_private_groups)
self.step("configuring netgroups from hostgroups", self.__host_nis_groups)
self.step("creating default Sudo bind user", self.__add_sudo_binduser)
+ self.step("creating default Auto Member layout", self.__add_automember_config)
if hbac_allow:
self.step("creating default HBAC rule allow_all", self.add_hbac)
@@ -283,6 +284,8 @@ class DsInstance(service.Service):
self.step("setting up initial replication", self.__setup_replica)
self.step("adding replication acis", self.__add_replication_acis)
+ # See LDIFs for automember configuration during replica install
+ self.step("setting Auto Member configuration", self.__add_replica_automember_config)
# Managed Entries configuration is done via update files
@@ -782,6 +785,12 @@ class DsInstance(service.Service):
def __add_sudo_binduser(self):
self._ldap_mod("sudobind.ldif", self.sub_dict)
+ def __add_automember_config(self):
+ self._ldap_mod("automember.ldif", self.sub_dict)
+
+ def __add_replica_automember_config(self):
+ self._ldap_mod("replica-automember.ldif", self.sub_dict)
+
def replica_populate(self):
self.ldap_connect()
diff --git a/tests/test_xmlrpc/objectclasses.py b/tests/test_xmlrpc/objectclasses.py
index 29cd6af..ce904d8 100644
--- a/tests/test_xmlrpc/objectclasses.py
+++ b/tests/test_xmlrpc/objectclasses.py
@@ -120,3 +120,8 @@ netgroup = [
u'ipaassociation',
u'ipanisnetgroup',
]
+
+automember = [
+ u'top',
+ u'automemberregexrule'
+]
diff --git a/tests/test_xmlrpc/test_automember_plugin.py b/tests/test_xmlrpc/test_automember_plugin.py
new file mode 100644
index 0000000..342bc21
--- /dev/null
+++ b/tests/test_xmlrpc/test_automember_plugin.py
@@ -0,0 +1,1074 @@
+# Authors:
+# Jr Aquino <jr.aquino@citrix.com>
+#
+# Copyright (C) 2011 Red Hat
+# see file 'COPYING' for use and warranty information
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+Test the `ipalib/plugins/automember.py` module.
+"""
+
+from ipalib import api, errors
+from tests.test_xmlrpc import objectclasses
+from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
+
+
+user1=u'tuser1'
+manager1=u'mscott'
+fqdn1 = u'web1.%s' % api.env.domain
+short1 = u'web1'
+fqdn2 = u'dev1.%s' % api.env.domain
+short2 = u'dev1'
+fqdn3 = u'web5.%s' % api.env.domain
+short3 = u'web5'
+fqdn4 = u'www5.%s' % api.env.domain
+short4 = u'www5'
+fqdn5 = u'webserver5.%s' % api.env.domain
+short5 = u'webserver5'
+
+group1=u'group1'
+defaultgroup1=u'defaultgroup1'
+hostgroup1=u'hostgroup1'
+hostgroup2=u'hostgroup2'
+hostgroup3=u'hostgroup3'
+hostgroup4=u'hostgroup4'
+defaulthostgroup1=u'defaulthostgroup1'
+
+group_include_regex = u'mscott'
+hostgroup_include_regex = u'^web[1-9]'
+hostgroup_include_regex2 = u'^www[1-9]'
+hostgroup_include_regex3 = u'webserver[1-9]'
+hostgroup_exclude_regex = u'^web5'
+hostgroup_exclude_regex2 = u'^www5'
+hostgroup_exclude_regex3 = u'^webserver5'
+
+
+class test_automember(Declarative):
+
+ cleanup_commands = [
+ ('user_del', [user1, manager1], {}),
+ ('group_del', [group1, defaultgroup1], {}),
+ ('host_del', [fqdn1, fqdn2, fqdn3, fqdn4, fqdn5], {}),
+ ('hostgroup_del', [hostgroup1, hostgroup2, hostgroup3, hostgroup4, defaulthostgroup1], {}),
+ ('automember_del', [group1], {'type': u'group'}),
+ ('automember_del', [hostgroup1], {'type': u'hostgroup'}),
+ ('automember_del', [hostgroup2], {'type': u'hostgroup'}),
+ ('automember_del', [hostgroup3], {'type': u'hostgroup'}),
+ ('automember_del', [hostgroup4], {'type': u'hostgroup'}),
+ ('automember_default_group_remove', [], {'type': u'hostgroup'}),
+ ('automember_default_group_remove', [], {'type': u'group'}),
+
+ ]
+
+ tests = [
+
+ dict(
+ desc='Try to retrieve non-existent %r' % user1,
+ command=('user_show', [user1], {}),
+ expected=errors.NotFound(reason='no such entry'),
+ ),
+
+
+ dict(
+ desc='Try to update non-existent %r' % user1,
+ command=('user_mod', [user1], dict(givenname=u'Foo')),
+ expected=errors.NotFound(reason='no such entry'),
+ ),
+
+
+ dict(
+ desc='Try to delete non-existent %r' % user1,
+ command=('user_del', [user1], {}),
+ expected=errors.NotFound(reason='no such entry'),
+ ),
+
+
+ dict(
+ desc='Try to rename non-existent %r' % user1,
+ command=('user_mod', [user1], dict(setattr=u'uid=tuser')),
+ expected=errors.NotFound(reason='no such entry'),
+ ),
+
+
+ dict(
+ desc='Create %r' % group1,
+ command=(
+ 'group_add', [group1], dict(description=u'Test desc')
+ ),
+ expected=dict(
+ value=group1,
+ summary=u'Added group "%s"' % group1,
+ result=dict(
+ cn=[group1],
+ description=[u'Test desc'],
+ gidnumber=[fuzzy_digits],
+ objectclass=objectclasses.group + [u'posixgroup'],
+ ipauniqueid=[fuzzy_uuid],
+ dn=u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % hostgroup1,
+ command=(
+ 'hostgroup_add', [hostgroup1], dict(description=u'Test desc')
+ ),
+ expected=dict(
+ value=hostgroup1,
+ summary=u'Added hostgroup "%s"' % hostgroup1,
+ result=dict(
+ cn=[hostgroup1],
+ description=[u'Test desc'],
+ objectclass=objectclasses.hostgroup,
+ ipauniqueid=[fuzzy_uuid],
+ memberof_netgroup=[u'hostgroup1'],
+ mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup1, api.env.basedn)],
+ dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % hostgroup2,
+ command=(
+ 'hostgroup_add', [hostgroup2], dict(description=u'Test desc')
+ ),
+ expected=dict(
+ value=hostgroup2,
+ summary=u'Added hostgroup "%s"' % hostgroup2,
+ result=dict(
+ cn=[hostgroup2],
+ description=[u'Test desc'],
+ objectclass=objectclasses.hostgroup,
+ ipauniqueid=[fuzzy_uuid],
+ memberof_netgroup=[u'hostgroup2'],
+ mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup2, api.env.basedn)],
+ dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % hostgroup3,
+ command=(
+ 'hostgroup_add', [hostgroup3], dict(description=u'Test desc')
+ ),
+ expected=dict(
+ value=hostgroup3,
+ summary=u'Added hostgroup "%s"' % hostgroup3,
+ result=dict(
+ cn=[hostgroup3],
+ description=[u'Test desc'],
+ objectclass=objectclasses.hostgroup,
+ ipauniqueid=[fuzzy_uuid],
+ memberof_netgroup=[u'hostgroup3'],
+ mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup3, api.env.basedn)],
+ dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % hostgroup4,
+ command=(
+ 'hostgroup_add', [hostgroup4], dict(description=u'Test desc')
+ ),
+ expected=dict(
+ value=hostgroup4,
+ summary=u'Added hostgroup "%s"' % hostgroup4,
+ result=dict(
+ cn=[hostgroup4],
+ description=[u'Test desc'],
+ objectclass=objectclasses.hostgroup,
+ ipauniqueid=[fuzzy_uuid],
+ memberof_netgroup=[u'hostgroup4'],
+ mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup4, api.env.basedn)],
+ dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % defaultgroup1,
+ command=(
+ 'group_add', [defaultgroup1], dict(description=u'Default test desc')
+ ),
+ expected=dict(
+ value=defaultgroup1,
+ summary=u'Added group "%s"' % defaultgroup1,
+ result=dict(
+ cn=[defaultgroup1],
+ description=[u'Default test desc'],
+ gidnumber=[fuzzy_digits],
+ objectclass=objectclasses.group + [u'posixgroup'],
+ ipauniqueid=[fuzzy_uuid],
+ dn=u'cn=%s,cn=groups,cn=accounts,%s' % (defaultgroup1, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % defaulthostgroup1,
+ command=(
+ 'hostgroup_add', [defaulthostgroup1], dict(description=u'Default test desc')
+ ),
+ expected=dict(
+ value=defaulthostgroup1,
+ summary=u'Added hostgroup "%s"' % defaulthostgroup1,
+ result=dict(
+ cn=[defaulthostgroup1],
+ description=[u'Default test desc'],
+ objectclass=objectclasses.hostgroup,
+ ipauniqueid=[fuzzy_uuid],
+ memberof_netgroup=[u'defaulthostgroup1'],
+ mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (defaulthostgroup1, api.env.basedn)],
+ dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember %r' % group1,
+ command=(
+ 'automember_add', [group1], dict(description=u'Test desc', type=u'group')
+ ),
+ expected=dict(
+ value=group1,
+ summary=u'Added automember rule "%s"' % group1,
+ result=dict(
+ cn=[group1],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ objectclass=objectclasses.automember,
+ dn=u'cn=%s,cn=group,cn=automember,cn=etc,%s' % (group1, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember condition %r' % group1,
+ command=(
+ 'automember_add_condition', [group1], dict(
+ key=u'manager', type=u'group',
+ automemberinclusiveregex=[group_include_regex],
+ )
+ ),
+ expected=dict(
+ value=group1,
+ summary=u'Added condition(s) to "%s"' % group1,
+ completed=1,
+ failed=dict(
+ failed = dict(
+ automemberinclusiveregex=tuple(),
+ automemberexclusiveregex=tuple(),
+ )
+ ),
+ result=dict(
+ cn=[group1],
+ description=[u'Test desc'],
+ automemberinclusiveregex=[u'manager=%s' % group_include_regex],
+ automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember %r' % hostgroup1,
+ command=(
+ 'automember_add', [hostgroup1], dict(
+ description=u'Test desc', type=u'hostgroup',
+ )
+ ),
+ expected=dict(
+ value=hostgroup1,
+ summary=u'Added automember rule "%s"' % hostgroup1,
+ result=dict(
+ cn=[hostgroup1],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ objectclass=objectclasses.automember,
+ dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup1, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember condition %r' % hostgroup1,
+ command=(
+ 'automember_add_condition', [hostgroup1], dict(
+ key=u'fqdn', type=u'hostgroup',
+ automemberinclusiveregex=[hostgroup_include_regex],
+ )
+ ),
+ expected=dict(
+ value=hostgroup1,
+ summary=u'Added condition(s) to "%s"' % hostgroup1,
+ completed=1,
+ failed=dict(
+ failed = dict(
+ automemberinclusiveregex=tuple(),
+ automemberexclusiveregex=tuple(),
+ )
+ ),
+ result=dict(
+ cn=[hostgroup1],
+ description=[u'Test desc'],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create duplicate automember condition %r' % hostgroup1,
+ command=(
+ 'automember_add_condition', [hostgroup1], dict(
+ key=u'fqdn', type=u'hostgroup',
+ automemberinclusiveregex=[hostgroup_include_regex],
+ )
+ ),
+ expected=dict(
+ value=hostgroup1,
+ summary=u'Added condition(s) to "%s"' % hostgroup1,
+ completed=0,
+ failed=dict(
+ failed = dict(
+ automemberinclusiveregex=tuple(),
+ automemberexclusiveregex=tuple(),
+ )
+ ),
+ result=dict(
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create additional automember conditions %r' % hostgroup1,
+ command=(
+ 'automember_add_condition', [hostgroup1], dict(
+ key=u'fqdn', type=u'hostgroup',
+ automemberinclusiveregex=[hostgroup_include_regex2, hostgroup_include_regex3],
+ automemberexclusiveregex=[hostgroup_exclude_regex, hostgroup_exclude_regex2, hostgroup_exclude_regex3],
+ )
+ ),
+ expected=dict(
+ value=hostgroup1,
+ summary=u'Added condition(s) to "%s"' % hostgroup1,
+ completed=5,
+ failed=dict(
+ failed = dict(
+ automemberinclusiveregex=tuple(),
+ automemberexclusiveregex=tuple(),
+ )
+ ),
+ result=dict(
+ cn=[hostgroup1],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
+ u'fqdn=%s' % hostgroup_include_regex3,
+ u'fqdn=%s' % hostgroup_include_regex2,
+ ],
+ automemberexclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex2,
+ u'fqdn=%s' % hostgroup_exclude_regex3,
+ u'fqdn=%s' % hostgroup_exclude_regex,
+ ],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember %r' % hostgroup2,
+ command=(
+ 'automember_add', [hostgroup2], dict(
+ description=u'Test desc', type=u'hostgroup',
+ )
+ ),
+ expected=dict(
+ value=hostgroup2,
+ summary=u'Added automember rule "%s"' % hostgroup2,
+ result=dict(
+ cn=[hostgroup2],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn)],
+ objectclass=objectclasses.automember,
+ dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup2, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember condition %r' % hostgroup2,
+ command=(
+ 'automember_add_condition', [hostgroup2], dict(
+ key=u'fqdn', type=u'hostgroup',
+ automemberinclusiveregex=[hostgroup_exclude_regex],
+ )
+ ),
+ expected=dict(
+ value=hostgroup2,
+ summary=u'Added condition(s) to "%s"' % hostgroup2,
+ completed=1,
+ failed=dict(
+ failed = dict(
+ automemberinclusiveregex=tuple(),
+ automemberexclusiveregex=tuple(),
+ )
+ ),
+ result=dict(
+ cn=[hostgroup2],
+ description=[u'Test desc'],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn)],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember %r' % hostgroup3,
+ command=(
+ 'automember_add', [hostgroup3], dict(
+ description=u'Test desc', type=u'hostgroup',
+ )
+ ),
+ expected=dict(
+ value=hostgroup3,
+ summary=u'Added automember rule "%s"' % hostgroup3,
+ result=dict(
+ cn=[hostgroup3],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn)],
+ objectclass=objectclasses.automember,
+ dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup3, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember condition %r' % hostgroup3,
+ command=(
+ 'automember_add_condition', [hostgroup3], dict(
+ key=u'fqdn', type=u'hostgroup',
+ automemberinclusiveregex=[hostgroup_exclude_regex2],
+ )
+ ),
+ expected=dict(
+ value=hostgroup3,
+ summary=u'Added condition(s) to "%s"' % hostgroup3,
+ completed=1,
+ failed=dict(
+ failed = dict(
+ automemberinclusiveregex=tuple(),
+ automemberexclusiveregex=tuple(),
+ )
+ ),
+ result=dict(
+ cn=[hostgroup3],
+ description=[u'Test desc'],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex2],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn)],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember %r' % hostgroup4,
+ command=(
+ 'automember_add', [hostgroup4], dict(
+ description=u'Test desc', type=u'hostgroup',
+ )
+ ),
+ expected=dict(
+ value=hostgroup4,
+ summary=u'Added automember rule "%s"' % hostgroup4,
+ result=dict(
+ cn=[hostgroup4],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn)],
+ objectclass=objectclasses.automember,
+ dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup4, api.env.basedn),
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create automember condition %r' % hostgroup4,
+ command=(
+ 'automember_add_condition', [hostgroup4], dict(
+ key=u'fqdn', type=u'hostgroup',
+ automemberinclusiveregex=[hostgroup_exclude_regex3],
+ )
+ ),
+ expected=dict(
+ value=hostgroup4,
+ summary=u'Added condition(s) to "%s"' % hostgroup4,
+ completed=1,
+ failed=dict(
+ failed = dict(
+ automemberinclusiveregex=tuple(),
+ automemberexclusiveregex=tuple(),
+ )
+ ),
+ result=dict(
+ cn=[hostgroup4],
+ description=[u'Test desc'],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex3],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn)],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc="Retrieve automember rule for group %s" % group1,
+ command=('automember_show', [group1], dict(
+ type=u'group',
+ )
+ ),
+ expected=dict(
+ value=group1,
+ result=dict(
+ cn=[group1],
+ description=[u'Test desc'],
+ automemberinclusiveregex=[u'manager=%s' % group_include_regex],
+ automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ dn=u'cn=%s,cn=group,cn=automember,cn=etc,%s' % (group1, api.env.basedn),
+ ),
+ summary=None,
+ ),
+ ),
+
+
+ dict(
+ desc='Search for %r' % group1,
+ command=('automember_find', [group1], dict(
+ type=u'group'
+ )
+ ),
+ expected=dict(
+ count=1,
+ truncated=False,
+ result=[
+ dict(
+ cn=[group1],
+ description=[u'Test desc'],
+ automemberinclusiveregex=[u'manager=%s' % group_include_regex],
+ automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ dn=u'cn=%s,cn=group,cn=automember,cn=etc,%s' % (group1, api.env.basedn),
+ ),
+ ],
+ summary=u'1 rules matched',
+ ),
+ ),
+
+
+ dict(
+ desc='Updated automember rule %r' % group1,
+ command=(
+ 'automember_mod', [group1], dict(
+ type=u'group',
+ description=u'New desc 1',
+ )
+ ),
+ expected=dict(
+ result=dict(
+ cn=[group1],
+ description=[u'New desc 1'],
+ automemberinclusiveregex=[u'manager=%s' % group_include_regex],
+ automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ ),
+ summary=u'Modified automember rule "%s"' % group1,
+ value=group1,
+ ),
+ ),
+
+
+ dict(
+ desc="Retrieve automember rule for hostgroup %s" % hostgroup1,
+ command=('automember_show', [hostgroup1], dict(
+ type=u'hostgroup',
+ )
+ ),
+ expected=dict(
+ value=hostgroup1,
+ result=dict(
+ cn=[hostgroup1],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
+ u'fqdn=%s' % hostgroup_include_regex3,
+ u'fqdn=%s' % hostgroup_include_regex2,
+ ],
+ automemberexclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex2,
+ u'fqdn=%s' % hostgroup_exclude_regex3,
+ u'fqdn=%s' % hostgroup_exclude_regex,
+ ],
+ dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup1, api.env.basedn),
+ ),
+ summary=None,
+ ),
+ ),
+
+
+ dict(
+ desc='Search for %r' % hostgroup1,
+ command=('automember_find', [hostgroup1], dict(
+ type=u'hostgroup'
+ )
+ ),
+ expected=dict(
+ count=1,
+ truncated=False,
+ result=[
+ dict(
+ cn=[hostgroup1],
+ description=[u'Test desc'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
+ u'fqdn=%s' % hostgroup_include_regex3,
+ u'fqdn=%s' % hostgroup_include_regex2,
+ ],
+ automemberexclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex2,
+ u'fqdn=%s' % hostgroup_exclude_regex3,
+ u'fqdn=%s' % hostgroup_exclude_regex,
+ ],
+ dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup1, api.env.basedn),
+ ),
+ ],
+ summary=u'1 rules matched',
+ ),
+ ),
+
+
+ dict(
+ desc='Updated automember rule %r' % hostgroup1,
+ command=(
+ 'automember_mod', [hostgroup1], dict(
+ type=u'hostgroup',
+ description=u'New desc 1',
+ )
+ ),
+ expected=dict(
+ result=dict(
+ cn=[hostgroup1],
+ description=[u'New desc 1'],
+ automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
+ u'fqdn=%s' % hostgroup_include_regex3,
+ u'fqdn=%s' % hostgroup_include_regex2,
+ ],
+ automemberexclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex2,
+ u'fqdn=%s' % hostgroup_exclude_regex3,
+ u'fqdn=%s' % hostgroup_exclude_regex,
+ ],
+ ),
+ summary=u'Modified automember rule "%s"' % hostgroup1,
+ value=hostgroup1,
+ ),
+ ),
+
+
+ dict(
+ desc='Set default automember group for groups',
+ command=(
+ 'automember_default_group_set', [], dict(
+ type=u'group',
+ automemberdefaultgroup=defaultgroup1
+ )
+ ),
+ expected=dict(
+ result=dict(
+ cn=[u'Group'],
+ automemberdefaultgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (defaultgroup1, api.env.basedn)],
+ ),
+ value=u'group',
+ summary=u'Set default group for automember "group"',
+ ),
+ ),
+
+
+ dict(
+ desc='Retrieve default automember group for groups',
+ command=(
+ 'automember_default_group_show', [], dict(
+ type=u'group',
+ automemberdefaultgroup=defaultgroup1,
+ )
+ ),
+ expected=dict(
+ result=dict(
+ dn=u'cn=group,cn=automember,cn=etc,%s' % (api.env.basedn),
+ cn=[u'Group'],
+ automemberdefaultgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (defaultgroup1, api.env.basedn)],
+ ),
+ value=u'group',
+ summary=None,
+ ),
+ ),
+
+
+ dict(
+ desc='Set default automember group for hostgroups',
+ command=(
+ 'automember_default_group_set', [], dict(
+ type=u'hostgroup',
+ automemberdefaultgroup=defaulthostgroup1,
+ )
+ ),
+ expected=dict(
+ result=dict(
+ cn=[u'Hostgroup'],
+ automemberdefaultgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn)],
+ ),
+ value=u'hostgroup',
+ summary=u'Set default group for automember "hostgroup"',
+ ),
+ ),
+
+
+ dict(
+ desc='Retrieve default automember group for hostgroups',
+ command=(
+ 'automember_default_group_show', [], dict(
+ type=u'hostgroup',
+ )
+ ),
+ expected=dict(
+ result=dict(
+ dn=u'cn=hostgroup,cn=automember,cn=etc,%s' % (api.env.basedn),
+ cn=[u'Hostgroup'],
+ automemberdefaultgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn)],
+ ),
+ value=u'hostgroup',
+ summary=None,
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % manager1,
+ command=(
+ 'user_add', [manager1], dict(givenname=u'Michael', sn=u'Scott')
+ ),
+ expected=dict(
+ value=manager1,
+ summary=u'Added user "mscott"',
+ result=dict(
+ gecos=[u'Michael Scott'],
+ givenname=[u'Michael'],
+ homedirectory=[u'/home/mscott'],
+ krbprincipalname=[u'mscott@' + api.env.realm],
+ has_keytab=False,
+ has_password=False,
+ loginshell=[u'/bin/sh'],
+ objectclass=objectclasses.user,
+ sn=[u'Scott'],
+ uid=[manager1],
+ uidnumber=[fuzzy_digits],
+ gidnumber=[fuzzy_digits],
+ displayname=[u'Michael Scott'],
+ cn=[u'Michael Scott'],
+ initials=[u'MS'],
+ ipauniqueid=[fuzzy_uuid],
+ krbpwdpolicyreference=[u'cn=global_policy,cn=%s,cn=kerberos,%s' % (api.env.realm, api.env.basedn)],
+ mepmanagedentry=[u'cn=%s,cn=groups,cn=accounts,%s' % (manager1, api.env.basedn)],
+ memberof_group=[u'defaultgroup1', u'ipausers'],
+ dn=u'uid=mscott,cn=users,cn=accounts,' + api.env.basedn,
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % user1,
+ command=(
+ 'user_add', [user1], dict(givenname=u'Test', sn=u'User1', manager=manager1)
+ ),
+ expected=dict(
+ value=user1,
+ summary=u'Added user "tuser1"',
+ result=dict(
+ gecos=[u'Test User1'],
+ givenname=[u'Test'],
+ homedirectory=[u'/home/tuser1'],
+ krbprincipalname=[u'tuser1@' + api.env.realm],
+ has_keytab=False,
+ has_password=False,
+ loginshell=[u'/bin/sh'],
+ objectclass=objectclasses.user,
+ sn=[u'User1'],
+ uid=[user1],
+ uidnumber=[fuzzy_digits],
+ gidnumber=[fuzzy_digits],
+ manager=[u'uid=mscott,cn=users,cn=accounts,%s' % api.env.basedn],
+ displayname=[u'Test User1'],
+ cn=[u'Test User1'],
+ initials=[u'TU'],
+ ipauniqueid=[fuzzy_uuid],
+ krbpwdpolicyreference=[u'cn=global_policy,cn=%s,cn=kerberos,%s' % (api.env.realm, api.env.basedn)],
+ mepmanagedentry=[u'cn=%s,cn=groups,cn=accounts,%s' % (user1, api.env.basedn)],
+ memberof_group=[u'group1', u'ipausers'],
+ dn=u'uid=tuser1,cn=users,cn=accounts,' + api.env.basedn,
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % fqdn1,
+ command=('host_add', [fqdn1],
+ dict(
+ description=u'Test host 1',
+ l=u'Undisclosed location 1',
+ force=True,
+ ),
+ ),
+ expected=dict(
+ value=fqdn1,
+ summary=u'Added host "%s"' % fqdn1,
+ result=dict(
+ dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn1, api.env.basedn),
+ fqdn=[fqdn1],
+ description=[u'Test host 1'],
+ l=[u'Undisclosed location 1'],
+ krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
+ has_keytab=False,
+ has_password=False,
+ objectclass=objectclasses.host,
+ ipauniqueid=[fuzzy_uuid],
+ managedby_host=[fqdn1],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % fqdn2,
+ command=('host_add', [fqdn2],
+ dict(
+ description=u'Test host 2',
+ l=u'Undisclosed location 1',
+ force=True,
+ ),
+ ),
+ expected=dict(
+ value=fqdn2,
+ summary=u'Added host "%s"' % fqdn2,
+ result=dict(
+ dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn2, api.env.basedn),
+ fqdn=[fqdn2],
+ description=[u'Test host 2'],
+ l=[u'Undisclosed location 1'],
+ krbprincipalname=[u'host/%s@%s' % (fqdn2, api.env.realm)],
+ has_keytab=False,
+ has_password=False,
+ objectclass=objectclasses.host,
+ ipauniqueid=[fuzzy_uuid],
+ managedby_host=[fqdn2],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % fqdn3,
+ command=('host_add', [fqdn3],
+ dict(
+ description=u'Test host 3',
+ l=u'Undisclosed location 1',
+ force=True,
+ ),
+ ),
+ expected=dict(
+ value=fqdn3,
+ summary=u'Added host "%s"' % fqdn3,
+ result=dict(
+ dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn3, api.env.basedn),
+ fqdn=[fqdn3],
+ description=[u'Test host 3'],
+ l=[u'Undisclosed location 1'],
+ krbprincipalname=[u'host/%s@%s' % (fqdn3, api.env.realm)],
+ has_keytab=False,
+ has_password=False,
+ objectclass=objectclasses.host,
+ ipauniqueid=[fuzzy_uuid],
+ managedby_host=[fqdn3],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % fqdn4,
+ command=('host_add', [fqdn4],
+ dict(
+ description=u'Test host 4',
+ l=u'Undisclosed location 1',
+ force=True,
+ ),
+ ),
+ expected=dict(
+ value=fqdn4,
+ summary=u'Added host "%s"' % fqdn4,
+ result=dict(
+ dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn4, api.env.basedn),
+ fqdn=[fqdn4],
+ description=[u'Test host 4'],
+ l=[u'Undisclosed location 1'],
+ krbprincipalname=[u'host/%s@%s' % (fqdn4, api.env.realm)],
+ has_keytab=False,
+ has_password=False,
+ objectclass=objectclasses.host,
+ ipauniqueid=[fuzzy_uuid],
+ managedby_host=[fqdn4],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Create %r' % fqdn5,
+ command=('host_add', [fqdn5],
+ dict(
+ description=u'Test host 5',
+ l=u'Undisclosed location 1',
+ force=True,
+ ),
+ ),
+ expected=dict(
+ value=fqdn5,
+ summary=u'Added host "%s"' % fqdn5,
+ result=dict(
+ dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn5, api.env.basedn),
+ fqdn=[fqdn5],
+ description=[u'Test host 5'],
+ l=[u'Undisclosed location 1'],
+ krbprincipalname=[u'host/%s@%s' % (fqdn5, api.env.realm)],
+ has_keytab=False,
+ has_password=False,
+ objectclass=objectclasses.host,
+ ipauniqueid=[fuzzy_uuid],
+ managedby_host=[fqdn5],
+ ),
+ ),
+ ),
+
+
+ dict(
+ desc='Retrieve %r' % hostgroup1,
+ command=('hostgroup_show', [hostgroup1], {}),
+ expected=dict(
+ value=hostgroup1,
+ summary=None,
+ result={
+ 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn),
+ 'member_host': [u'%s' % fqdn1],
+ 'cn': [hostgroup1],
+ 'description': [u'Test desc'],
+ 'memberof_netgroup': [u'hostgroup1'],
+ },
+ ),
+ ),
+
+
+ dict(
+ desc='Retrieve %r' % defaulthostgroup1,
+ command=('hostgroup_show', [defaulthostgroup1], {}),
+ expected=dict(
+ value=defaulthostgroup1,
+ summary=None,
+ result={
+ 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn),
+ 'member_host': [u'%s' % fqdn2],
+ 'cn': [defaulthostgroup1],
+ 'description': [u'Default test desc'],
+ 'memberof_netgroup': [u'defaulthostgroup1'],
+ },
+ ),
+ ),
+
+
+ dict(
+ desc='Retrieve %r' % hostgroup2,
+ command=('hostgroup_show', [hostgroup2], {}),
+ expected=dict(
+ value=hostgroup2,
+ summary=None,
+ result={
+ 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn),
+ 'member_host': [u'%s' % fqdn3],
+ 'cn': [hostgroup2],
+ 'description': [u'Test desc'],
+ 'memberof_netgroup': [u'hostgroup2'],
+ },
+ ),
+ ),
+
+
+ dict(
+ desc='Retrieve %r' % hostgroup3,
+ command=('hostgroup_show', [hostgroup3], {}),
+ expected=dict(
+ value=hostgroup3,
+ summary=None,
+ result={
+ 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn),
+ 'member_host': [u'%s' % fqdn4],
+ 'cn': [hostgroup3],
+ 'description': [u'Test desc'],
+ 'memberof_netgroup': [u'hostgroup3'],
+ },
+ ),
+ ),
+
+
+ dict(
+ desc='Retrieve %r' % hostgroup4,
+ command=('hostgroup_show', [hostgroup4], {}),
+ expected=dict(
+ value=hostgroup4,
+ summary=None,
+ result={
+ 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn),
+ 'member_host': [u'%s' % fqdn5],
+ 'cn': [hostgroup4],
+ 'description': [u'Test desc'],
+ 'memberof_netgroup': [u'hostgroup4'],
+ },
+ ),
+ ),
+
+ ] \ No newline at end of file