From 12d662c1b76fc5971e23471617ebdf2a14ea9cfa Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 13 Aug 2008 01:18:00 +0000 Subject: 131: Renamed Plugins/ to plugins/ --- ipalib/plugins/__init__.py | 24 +++++++ ipalib/plugins/example.py | 156 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 ipalib/plugins/__init__.py create mode 100644 ipalib/plugins/example.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/__init__.py b/ipalib/plugins/__init__.py new file mode 100644 index 00000000..743eedb9 --- /dev/null +++ b/ipalib/plugins/__init__.py @@ -0,0 +1,24 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Sub-package containing all internal plugins. +""" + +import example diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py new file mode 100644 index 00000000..49b3d49c --- /dev/null +++ b/ipalib/plugins/example.py @@ -0,0 +1,156 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Some example plugins. +""" + + +from ipalib import public +from ipalib.run import api + + +# Hypothetical functional commands (not associated with any object): +class krbtest(public.cmd): + def get_doc(self, _): + return _('test your Kerberos ticket') +api.register(krbtest) + +class discover(public.cmd): + def get_doc(self, _): + return _('discover IPA servers on network') +api.register(discover) + + +# Register some methods for the 'user' object: +class user_add(public.mthd): + def get_doc(self, _): + return _('add new user') +api.register(user_add) + +class user_del(public.mthd): + def get_doc(self, _): + return _('delete existing user') +api.register(user_del) + +class user_mod(public.mthd): + def get_doc(self, _): + return _('edit existing user') +api.register(user_mod) + +class user_find(public.mthd): + def get_doc(self, _): + return _('search for users') +api.register(user_find) + + +# Register some properties for the 'user' object: +class user_givenname(public.prop): + def get_doc(self, _): + return _('user first name') +api.register(user_givenname) + +class user_sn(public.prop): + def get_doc(self, _): + return _('user last name') +api.register(user_sn) + +class user_login(public.prop): + def get_doc(self, _): + return _('user login') + def default(self, **kw): + givenname = kw.get('givenname', None) + sn = kw.get('sn', None) + if givenname is None or sn is None: + return None + return ('%s%s' % (givenname[0], sn)).lower() +api.register(user_login) + +class user_initials(public.prop): + def get_doc(self, _): + return _('user initials') + def default(self, **kw): + givenname = kw.get('givenname', None) + sn = kw.get('sn', None) + if givenname is None or sn is None: + return None + return '%s%s' % (givenname[0], sn[0]) +api.register(user_initials) + + +# Register some methods for the 'group' object: +class group_add(public.mthd): + def get_doc(self, _): + return _('add new group') +api.register(group_add) + +class group_del(public.mthd): + def get_doc(self, _): + return _('delete existing group') +api.register(group_del) + +class group_mod(public.mthd): + def get_doc(self, _): + return _('edit existing group') +api.register(group_mod) + +class group_find(public.mthd): + def get_doc(self, _): + return _('search for groups') +api.register(group_find) + + +# Register some methods for the 'service' object +class service_add(public.mthd): + def get_doc(self, _): + return _('add new service') +api.register(service_add) + +class service_del(public.mthd): + def get_doc(self, _): + return _('delete existing service') +api.register(service_del) + +class service_mod(public.mthd): + def get_doc(self, _): + return _('edit existing service') +api.register(service_mod) + +class service_find(public.mthd): + def get_doc(self, _): + return _('search for services') +api.register(service_find) + + +# And to emphasis that the registration order doesn't matter, +# we'll register the objects last: +class group(public.obj): + def get_doc(self, _): + return _('') +api.register(group) + +class service(public.obj): + def get_doc(self, _): + return _('') +api.register(service) + +class user(public.obj): + def get_doc(self, _): + return _('') +api.register(user) -- cgit From c0b5069fa07889496786523c46b5b15181c26fee Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 13 Aug 2008 01:26:30 +0000 Subject: 133: Renamed run.py to api.py --- ipalib/plugins/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 49b3d49c..caf963d2 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -23,7 +23,7 @@ Some example plugins. from ipalib import public -from ipalib.run import api +from ipalib.api import api # Hypothetical functional commands (not associated with any object): -- cgit From 0fed74b56d1940f84e7b64c3661f21baabcb4616 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 13 Aug 2008 02:34:36 +0000 Subject: 138: Added ProxyTarget.doc property; CLI.print_commands() now uses cmd.doc instead of cmd.get_doc() --- ipalib/plugins/example.py | 63 ++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 42 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index caf963d2..770ed33b 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -28,52 +28,43 @@ from ipalib.api import api # Hypothetical functional commands (not associated with any object): class krbtest(public.cmd): - def get_doc(self, _): - return _('test your Kerberos ticket') + 'test your Kerberos ticket' api.register(krbtest) class discover(public.cmd): - def get_doc(self, _): - return _('discover IPA servers on network') + 'discover IPA servers on network' api.register(discover) # Register some methods for the 'user' object: class user_add(public.mthd): - def get_doc(self, _): - return _('add new user') + 'add new user' api.register(user_add) class user_del(public.mthd): - def get_doc(self, _): - return _('delete existing user') + 'delete existing user' api.register(user_del) class user_mod(public.mthd): - def get_doc(self, _): - return _('edit existing user') + 'edit existing user' api.register(user_mod) class user_find(public.mthd): - def get_doc(self, _): - return _('search for users') + 'search for users' api.register(user_find) # Register some properties for the 'user' object: class user_givenname(public.prop): - def get_doc(self, _): - return _('user first name') + 'user first name' api.register(user_givenname) class user_sn(public.prop): - def get_doc(self, _): - return _('user last name') + 'user last name' api.register(user_sn) class user_login(public.prop): - def get_doc(self, _): - return _('user login') + 'user login' def default(self, **kw): givenname = kw.get('givenname', None) sn = kw.get('sn', None) @@ -83,8 +74,7 @@ class user_login(public.prop): api.register(user_login) class user_initials(public.prop): - def get_doc(self, _): - return _('user initials') + 'user initials' def default(self, **kw): givenname = kw.get('givenname', None) sn = kw.get('sn', None) @@ -96,61 +86,50 @@ api.register(user_initials) # Register some methods for the 'group' object: class group_add(public.mthd): - def get_doc(self, _): - return _('add new group') + 'add new group' api.register(group_add) class group_del(public.mthd): - def get_doc(self, _): - return _('delete existing group') + 'delete existing group' api.register(group_del) class group_mod(public.mthd): - def get_doc(self, _): - return _('edit existing group') + 'edit existing group' api.register(group_mod) class group_find(public.mthd): - def get_doc(self, _): - return _('search for groups') + 'search for groups' api.register(group_find) # Register some methods for the 'service' object class service_add(public.mthd): - def get_doc(self, _): - return _('add new service') + 'add new service' api.register(service_add) class service_del(public.mthd): - def get_doc(self, _): - return _('delete existing service') + 'delete existing service' api.register(service_del) class service_mod(public.mthd): - def get_doc(self, _): - return _('edit existing service') + 'edit existing service' api.register(service_mod) class service_find(public.mthd): - def get_doc(self, _): - return _('search for services') + 'search for services' api.register(service_find) # And to emphasis that the registration order doesn't matter, # we'll register the objects last: class group(public.obj): - def get_doc(self, _): - return _('') + 'group object' api.register(group) class service(public.obj): - def get_doc(self, _): - return _('') + 'service object' api.register(service) class user(public.obj): - def get_doc(self, _): - return _('') + 'user object' api.register(user) -- cgit From 6924d5e25e237244e20554c380454a4029a0288f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 13 Aug 2008 05:25:00 +0000 Subject: 144: Made properties in example plugins all required --- ipalib/plugins/example.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 770ed33b..b5bd4733 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -57,14 +57,17 @@ api.register(user_find) # Register some properties for the 'user' object: class user_givenname(public.prop): 'user first name' + required = True api.register(user_givenname) class user_sn(public.prop): 'user last name' + required = True api.register(user_sn) class user_login(public.prop): 'user login' + required = True def default(self, **kw): givenname = kw.get('givenname', None) sn = kw.get('sn', None) @@ -75,6 +78,7 @@ api.register(user_login) class user_initials(public.prop): 'user initials' + required = True def default(self, **kw): givenname = kw.get('givenname', None) sn = kw.get('sn', None) -- cgit From 99450358af821b269d46581750d20730fb5c9e9f Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 15 Aug 2008 19:19:42 +0000 Subject: 181: Changed docstrings on example plugins to use itial capital --- ipalib/plugins/example.py | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index b5bd4733..3350e2b9 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -28,45 +28,45 @@ from ipalib.api import api # Hypothetical functional commands (not associated with any object): class krbtest(public.cmd): - 'test your Kerberos ticket' + 'Test your Kerberos ticket' api.register(krbtest) class discover(public.cmd): - 'discover IPA servers on network' + 'Discover IPA servers on network' api.register(discover) # Register some methods for the 'user' object: class user_add(public.mthd): - 'add new user' + 'Add new user' api.register(user_add) class user_del(public.mthd): - 'delete existing user' + 'Delete existing user' api.register(user_del) class user_mod(public.mthd): - 'edit existing user' + 'Edit existing user' api.register(user_mod) class user_find(public.mthd): - 'search for users' + 'Search for users' api.register(user_find) # Register some properties for the 'user' object: class user_givenname(public.prop): - 'user first name' + 'User first name' required = True api.register(user_givenname) class user_sn(public.prop): - 'user last name' + 'User last name' required = True api.register(user_sn) class user_login(public.prop): - 'user login' + 'User login' required = True def default(self, **kw): givenname = kw.get('givenname', None) @@ -77,7 +77,7 @@ class user_login(public.prop): api.register(user_login) class user_initials(public.prop): - 'user initials' + 'User initials' required = True def default(self, **kw): givenname = kw.get('givenname', None) @@ -90,50 +90,50 @@ api.register(user_initials) # Register some methods for the 'group' object: class group_add(public.mthd): - 'add new group' + 'Add new group' api.register(group_add) class group_del(public.mthd): - 'delete existing group' + 'Delete existing group' api.register(group_del) class group_mod(public.mthd): - 'edit existing group' + 'Edit existing group' api.register(group_mod) class group_find(public.mthd): - 'search for groups' + 'Search for groups' api.register(group_find) # Register some methods for the 'service' object class service_add(public.mthd): - 'add new service' + 'Add new service' api.register(service_add) class service_del(public.mthd): - 'delete existing service' + 'Delete existing service' api.register(service_del) class service_mod(public.mthd): - 'edit existing service' + 'Edit existing service' api.register(service_mod) class service_find(public.mthd): - 'search for services' + 'Search for services' api.register(service_find) # And to emphasis that the registration order doesn't matter, # we'll register the objects last: class group(public.obj): - 'group object' + 'Group object' api.register(group) class service(public.obj): - 'service object' + 'Service object' api.register(service) class user(public.obj): - 'user object' + 'User object' api.register(user) -- cgit From b0ec8fe551bc5f454aa1babeab31a424fd8c9abe Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 15 Aug 2008 19:49:04 +0000 Subject: 182: Renamed plublic.cmd base class to Command --- ipalib/plugins/example.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 3350e2b9..8a89ca43 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -27,11 +27,11 @@ from ipalib.api import api # Hypothetical functional commands (not associated with any object): -class krbtest(public.cmd): +class krbtest(public.Command): 'Test your Kerberos ticket' api.register(krbtest) -class discover(public.cmd): +class discover(public.Command): 'Discover IPA servers on network' api.register(discover) -- cgit From a1b5d928fbf989a45c0fabb599d25e80964aacee Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 22 Aug 2008 20:23:19 +0000 Subject: 184: Renamed public.mthd class to Method --- ipalib/plugins/example.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 8a89ca43..30f0a70f 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -37,19 +37,19 @@ api.register(discover) # Register some methods for the 'user' object: -class user_add(public.mthd): +class user_add(public.Method): 'Add new user' api.register(user_add) -class user_del(public.mthd): +class user_del(public.Method): 'Delete existing user' api.register(user_del) -class user_mod(public.mthd): +class user_mod(public.Method): 'Edit existing user' api.register(user_mod) -class user_find(public.mthd): +class user_find(public.Method): 'Search for users' api.register(user_find) @@ -89,37 +89,37 @@ api.register(user_initials) # Register some methods for the 'group' object: -class group_add(public.mthd): +class group_add(public.Method): 'Add new group' api.register(group_add) -class group_del(public.mthd): +class group_del(public.Method): 'Delete existing group' api.register(group_del) -class group_mod(public.mthd): +class group_mod(public.Method): 'Edit existing group' api.register(group_mod) -class group_find(public.mthd): +class group_find(public.Method): 'Search for groups' api.register(group_find) # Register some methods for the 'service' object -class service_add(public.mthd): +class service_add(public.Method): 'Add new service' api.register(service_add) -class service_del(public.mthd): +class service_del(public.Method): 'Delete existing service' api.register(service_del) -class service_mod(public.mthd): +class service_mod(public.Method): 'Edit existing service' api.register(service_mod) -class service_find(public.mthd): +class service_find(public.Method): 'Search for services' api.register(service_find) -- cgit From 5bf6a9eb097fbaf1c048a4487e6ca6b9605b9f05 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 22 Aug 2008 20:32:23 +0000 Subject: 185: Renamed public.prop to Property --- ipalib/plugins/example.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 30f0a70f..cff144ba 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -55,17 +55,17 @@ api.register(user_find) # Register some properties for the 'user' object: -class user_givenname(public.prop): +class user_givenname(public.Property): 'User first name' required = True api.register(user_givenname) -class user_sn(public.prop): +class user_sn(public.Property): 'User last name' required = True api.register(user_sn) -class user_login(public.prop): +class user_login(public.Property): 'User login' required = True def default(self, **kw): @@ -76,7 +76,7 @@ class user_login(public.prop): return ('%s%s' % (givenname[0], sn)).lower() api.register(user_login) -class user_initials(public.prop): +class user_initials(public.Property): 'User initials' required = True def default(self, **kw): -- cgit From af52671e132818deaf266cd434338aff11064f01 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 22 Aug 2008 21:50:53 +0000 Subject: 187: Renamed plubic.obj to Object; reworked plublic.Object unit tests to use ClassChecker --- ipalib/plugins/example.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index cff144ba..f7a5fe70 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -126,14 +126,14 @@ api.register(service_find) # And to emphasis that the registration order doesn't matter, # we'll register the objects last: -class group(public.obj): +class group(public.Object): 'Group object' api.register(group) -class service(public.obj): +class service(public.Object): 'Service object' api.register(service) -class user(public.obj): +class user(public.Object): 'User object' api.register(user) -- cgit From 2fc3819beca86c3d19d85e2f5777af3566305175 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 25 Aug 2008 23:35:29 +0000 Subject: 191: Removed ipalib/api.py module; standard plugable.API instance is now in ipalib.__init__.py --- ipalib/plugins/example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index f7a5fe70..4f960564 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -23,7 +23,7 @@ Some example plugins. from ipalib import public -from ipalib.api import api +from ipalib import api # Hypothetical functional commands (not associated with any object): -- cgit From 6226837eeae1ff8dca4a7bfe470337936c08dbaa Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 26 Aug 2008 19:23:50 +0000 Subject: 199: Updated user_login and user_initials example plugins to use Option.default_from --- ipalib/plugins/example.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 4f960564..3456b1dc 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -68,23 +68,19 @@ api.register(user_sn) class user_login(public.Property): 'User login' required = True - def default(self, **kw): - givenname = kw.get('givenname', None) - sn = kw.get('sn', None) - if givenname is None or sn is None: - return None - return ('%s%s' % (givenname[0], sn)).lower() + default_from = public.DefaultFrom( + lambda first, last: (first[0] + last).lower(), + 'givenname', 'sn' + ) api.register(user_login) class user_initials(public.Property): 'User initials' required = True - def default(self, **kw): - givenname = kw.get('givenname', None) - sn = kw.get('sn', None) - if givenname is None or sn is None: - return None - return '%s%s' % (givenname[0], sn[0]) + default_from = public.DefaultFrom( + lambda first, last: first[0] + last[0], + 'givenname', 'sn' + ) api.register(user_initials) -- cgit From 74a3cf8d2860665cc37a8f2787f950246c0ba10e Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 26 Aug 2008 19:43:56 +0000 Subject: 200: Added plugins/override.py with an example of overriding a plugin --- ipalib/plugins/__init__.py | 1 + ipalib/plugins/override.py | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 ipalib/plugins/override.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/__init__.py b/ipalib/plugins/__init__.py index 743eedb9..91b56733 100644 --- a/ipalib/plugins/__init__.py +++ b/ipalib/plugins/__init__.py @@ -22,3 +22,4 @@ Sub-package containing all internal plugins. """ import example +import override diff --git a/ipalib/plugins/override.py b/ipalib/plugins/override.py new file mode 100644 index 00000000..bc5666c2 --- /dev/null +++ b/ipalib/plugins/override.py @@ -0,0 +1,33 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +An example of overriding a plugin. + +This example depends upon the order that the plugins/ modules are imported +in plugins/__init__.py, which will likely change in the near future. +""" + +from ipalib import public +from ipalib import api + +if 'user_mod' in api.register.Method: + class user_mod(api.register.Method.user_mod): + '(override) Edit existing user' + api.register(user_mod, override=True) -- cgit From b16deabdffd19dcc6f85f3c1f03074484669912c Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 4 Sep 2008 05:18:14 +0000 Subject: 256: Fixed cli.help plugin so it looks up commands in CLI instead of API --- ipalib/plugins/example.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 3456b1dc..ab752976 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -38,19 +38,19 @@ api.register(discover) # Register some methods for the 'user' object: class user_add(public.Method): - 'Add new user' + 'Add a new user.' api.register(user_add) class user_del(public.Method): - 'Delete existing user' + 'Delete an existing user.' api.register(user_del) class user_mod(public.Method): - 'Edit existing user' + 'Edit an existing user.' api.register(user_mod) class user_find(public.Method): - 'Search for users' + 'Search for existing users.' api.register(user_find) -- cgit From 553b0c596d9dc1a955aece1fab28bd0cf3c81119 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 4 Sep 2008 09:22:18 +0000 Subject: 264: Cleaned up docstrings on all example plugins --- ipalib/plugins/example.py | 22 +++++++++++----------- ipalib/plugins/override.py | 5 +++-- 2 files changed, 14 insertions(+), 13 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index ab752976..4c62a5de 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -28,11 +28,11 @@ from ipalib import api # Hypothetical functional commands (not associated with any object): class krbtest(public.Command): - 'Test your Kerberos ticket' + 'Test your Kerberos ticket.' api.register(krbtest) class discover(public.Command): - 'Discover IPA servers on network' + 'Discover IPA servers on network.' api.register(discover) @@ -50,7 +50,7 @@ class user_mod(public.Method): api.register(user_mod) class user_find(public.Method): - 'Search for existing users.' + 'Search the users.' api.register(user_find) @@ -86,37 +86,37 @@ api.register(user_initials) # Register some methods for the 'group' object: class group_add(public.Method): - 'Add new group' + 'Add a new group.' api.register(group_add) class group_del(public.Method): - 'Delete existing group' + 'Delete an existing group.' api.register(group_del) class group_mod(public.Method): - 'Edit existing group' + 'Edit an existing group.' api.register(group_mod) class group_find(public.Method): - 'Search for groups' + 'Search the groups.' api.register(group_find) # Register some methods for the 'service' object class service_add(public.Method): - 'Add new service' + 'Add a new service.' api.register(service_add) class service_del(public.Method): - 'Delete existing service' + 'Delete an existing service.' api.register(service_del) class service_mod(public.Method): - 'Edit existing service' + 'Edit an existing service.' api.register(service_mod) class service_find(public.Method): - 'Search for services' + 'Search the services.' api.register(service_find) diff --git a/ipalib/plugins/override.py b/ipalib/plugins/override.py index bc5666c2..1255eae7 100644 --- a/ipalib/plugins/override.py +++ b/ipalib/plugins/override.py @@ -28,6 +28,7 @@ from ipalib import public from ipalib import api if 'user_mod' in api.register.Method: - class user_mod(api.register.Method.user_mod): - '(override) Edit existing user' + base = api.register.Method.user_mod + class user_mod(base): + 'Example override, see ipalib/plugins/override.py' api.register(user_mod, override=True) -- cgit From 0e60036bb4db8cf505a3f1009023a09ca2ffe0a1 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 12 Sep 2008 16:36:04 +0000 Subject: 290: Applyied Rob's patch --- ipalib/plugins/example.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 4c62a5de..92ef95d5 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -24,7 +24,8 @@ Some example plugins. from ipalib import public from ipalib import api - +from ipalib import servercore +import ldap # Hypothetical functional commands (not associated with any object): class krbtest(public.Command): @@ -39,8 +40,11 @@ api.register(discover) # Register some methods for the 'user' object: class user_add(public.Method): 'Add a new user.' + def execute(self, **kw): + return 1 api.register(user_add) + class user_del(public.Method): 'Delete an existing user.' api.register(user_del) @@ -51,6 +55,9 @@ api.register(user_mod) class user_find(public.Method): 'Search the users.' + def execute(self, **kw): + result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % kw['uid'], ["*"]) + return result api.register(user_find) -- cgit From 5a1abcdf4ff3433bcce15cd336660d73ab7c8d5b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sat, 13 Sep 2008 00:22:01 +0000 Subject: 291: Temporarily reverted Rob's changes in public.py and plugins/examples.py --- ipalib/plugins/example.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 92ef95d5..4c62a5de 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -24,8 +24,7 @@ Some example plugins. from ipalib import public from ipalib import api -from ipalib import servercore -import ldap + # Hypothetical functional commands (not associated with any object): class krbtest(public.Command): @@ -40,11 +39,8 @@ api.register(discover) # Register some methods for the 'user' object: class user_add(public.Method): 'Add a new user.' - def execute(self, **kw): - return 1 api.register(user_add) - class user_del(public.Method): 'Delete an existing user.' api.register(user_del) @@ -55,9 +51,6 @@ api.register(user_mod) class user_find(public.Method): 'Search the users.' - def execute(self, **kw): - result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % kw['uid'], ["*"]) - return result api.register(user_find) -- cgit From 2d836140064154c461aec1b24ae8d774cbd12444 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 21 Sep 2008 19:00:41 +0000 Subject: 305: Ported cli.py to changes in public.py --- ipalib/plugins/example.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 4c62a5de..74874c95 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -39,6 +39,15 @@ api.register(discover) # Register some methods for the 'user' object: class user_add(public.Method): 'Add a new user.' + + takes_args = ['login'] + + takes_options = [ + 'givenname', + 'sn', + 'initials', + ] + api.register(user_add) class user_del(public.Method): -- cgit From 47e4606a98ad4dd4ca05a6ede81e6ceb164568ee Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 21 Sep 2008 21:55:21 +0000 Subject: 308: Fixed broken example plugin user_add --- ipalib/plugins/example.py | 9 --------- 1 file changed, 9 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 74874c95..4c62a5de 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -39,15 +39,6 @@ api.register(discover) # Register some methods for the 'user' object: class user_add(public.Method): 'Add a new user.' - - takes_args = ['login'] - - takes_options = [ - 'givenname', - 'sn', - 'initials', - ] - api.register(user_add) class user_del(public.Method): -- cgit From 4e8ff5c65675fe7534afa02ce06d6ff73fd024c9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 24 Sep 2008 00:01:29 +0000 Subject: 318: Renamed all references to 'public' module to 'frontend' --- ipalib/plugins/example.py | 48 +++++++++++++++++++++++----------------------- ipalib/plugins/override.py | 1 - 2 files changed, 24 insertions(+), 25 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 4c62a5de..24bf5b8f 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -22,62 +22,62 @@ Some example plugins. """ -from ipalib import public +from ipalib import frontend from ipalib import api # Hypothetical functional commands (not associated with any object): -class krbtest(public.Command): +class krbtest(frontend.Command): 'Test your Kerberos ticket.' api.register(krbtest) -class discover(public.Command): +class discover(frontend.Command): 'Discover IPA servers on network.' api.register(discover) # Register some methods for the 'user' object: -class user_add(public.Method): +class user_add(frontend.Method): 'Add a new user.' api.register(user_add) -class user_del(public.Method): +class user_del(frontend.Method): 'Delete an existing user.' api.register(user_del) -class user_mod(public.Method): +class user_mod(frontend.Method): 'Edit an existing user.' api.register(user_mod) -class user_find(public.Method): +class user_find(frontend.Method): 'Search the users.' api.register(user_find) # Register some properties for the 'user' object: -class user_givenname(public.Property): +class user_givenname(frontend.Property): 'User first name' required = True api.register(user_givenname) -class user_sn(public.Property): +class user_sn(frontend.Property): 'User last name' required = True api.register(user_sn) -class user_login(public.Property): +class user_login(frontend.Property): 'User login' required = True - default_from = public.DefaultFrom( + default_from = frontend.DefaultFrom( lambda first, last: (first[0] + last).lower(), 'givenname', 'sn' ) api.register(user_login) -class user_initials(public.Property): +class user_initials(frontend.Property): 'User initials' required = True - default_from = public.DefaultFrom( + default_from = frontend.DefaultFrom( lambda first, last: first[0] + last[0], 'givenname', 'sn' ) @@ -85,51 +85,51 @@ api.register(user_initials) # Register some methods for the 'group' object: -class group_add(public.Method): +class group_add(frontend.Method): 'Add a new group.' api.register(group_add) -class group_del(public.Method): +class group_del(frontend.Method): 'Delete an existing group.' api.register(group_del) -class group_mod(public.Method): +class group_mod(frontend.Method): 'Edit an existing group.' api.register(group_mod) -class group_find(public.Method): +class group_find(frontend.Method): 'Search the groups.' api.register(group_find) # Register some methods for the 'service' object -class service_add(public.Method): +class service_add(frontend.Method): 'Add a new service.' api.register(service_add) -class service_del(public.Method): +class service_del(frontend.Method): 'Delete an existing service.' api.register(service_del) -class service_mod(public.Method): +class service_mod(frontend.Method): 'Edit an existing service.' api.register(service_mod) -class service_find(public.Method): +class service_find(frontend.Method): 'Search the services.' api.register(service_find) # And to emphasis that the registration order doesn't matter, # we'll register the objects last: -class group(public.Object): +class group(frontend.Object): 'Group object' api.register(group) -class service(public.Object): +class service(frontend.Object): 'Service object' api.register(service) -class user(public.Object): +class user(frontend.Object): 'User object' api.register(user) diff --git a/ipalib/plugins/override.py b/ipalib/plugins/override.py index 1255eae7..29ec2509 100644 --- a/ipalib/plugins/override.py +++ b/ipalib/plugins/override.py @@ -24,7 +24,6 @@ This example depends upon the order that the plugins/ modules are imported in plugins/__init__.py, which will likely change in the near future. """ -from ipalib import public from ipalib import api if 'user_mod' in api.register.Method: -- cgit From 4747563a802a08863d2195222b2f428e52af8502 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 25 Sep 2008 00:42:38 +0000 Subject: 356: Modified Method.get_options() to now pull from self.obj.params(); updated unit tests for Method.get_options() --- ipalib/plugins/example.py | 61 ++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 24bf5b8f..143f9f29 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -23,6 +23,7 @@ Some example plugins. from ipalib import frontend +from ipalib.frontend import Param from ipalib import api @@ -55,33 +56,33 @@ api.register(user_find) # Register some properties for the 'user' object: -class user_givenname(frontend.Property): - 'User first name' - required = True -api.register(user_givenname) - -class user_sn(frontend.Property): - 'User last name' - required = True -api.register(user_sn) - -class user_login(frontend.Property): - 'User login' - required = True - default_from = frontend.DefaultFrom( - lambda first, last: (first[0] + last).lower(), - 'givenname', 'sn' - ) -api.register(user_login) - -class user_initials(frontend.Property): - 'User initials' - required = True - default_from = frontend.DefaultFrom( - lambda first, last: first[0] + last[0], - 'givenname', 'sn' - ) -api.register(user_initials) +#class user_givenname(frontend.Property): +# 'User first name' +# required = True +#api.register(user_givenname) + +#class user_sn(frontend.Property): +# 'User last name' +# required = True +#api.register(user_sn) + +#class user_login(frontend.Property): +# 'User login' +# required = True +# default_from = frontend.DefaultFrom( +# lambda first, last: (first[0] + last).lower(), +# 'givenname', 'sn' +# ) +#api.register(user_login) + +#class user_initials(frontend.Property): +# 'User initials' +# required = True +# default_from = frontend.DefaultFrom( +# lambda first, last: first[0] + last[0], +# 'givenname', 'sn' +# ) +#api.register(user_initials) # Register some methods for the 'group' object: @@ -132,4 +133,10 @@ api.register(service) class user(frontend.Object): 'User object' + takes_params = ( + 'givenname', + 'sn', + 'uid', + 'krbprincipalname', + ) api.register(user) -- cgit From e84dd7a69d6f0ab83ec00c4207186ad189ec7cb9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 25 Sep 2008 00:58:16 +0000 Subject: 357: Some experimenting with the example plugins --- ipalib/plugins/example.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 143f9f29..36af33cd 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -27,6 +27,26 @@ from ipalib.frontend import Param from ipalib import api +class user(frontend.Object): + 'User object' + takes_params = ( + 'givenname', + 'sn', + Param('uid', + primary_key=True, + default_from=lambda givenname, sn: givenname[0] + sn, + normalize=lambda value: value.lower(), + ), + Param('krbprincipalname', + default_from=lambda uid: '%s@EXAMPLE.COM' % uid, + ), + Param('homedirectory', + default_from=lambda uid: '/home/%s' % uid, + ) + ) +api.register(user) + + # Hypothetical functional commands (not associated with any object): class krbtest(frontend.Command): 'Test your Kerberos ticket.' @@ -130,13 +150,3 @@ api.register(group) class service(frontend.Object): 'Service object' api.register(service) - -class user(frontend.Object): - 'User object' - takes_params = ( - 'givenname', - 'sn', - 'uid', - 'krbprincipalname', - ) -api.register(user) -- cgit From ac88500382084d3c24a73c15c5fcfe02660383f7 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 25 Sep 2008 03:58:42 +0000 Subject: 366: Ported user_* example Commands to crud base classes; added user_show example command --- ipalib/plugins/example.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 36af33cd..7576d2a1 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -23,6 +23,7 @@ Some example plugins. from ipalib import frontend +from ipalib import crud from ipalib.frontend import Param from ipalib import api @@ -58,22 +59,26 @@ api.register(discover) # Register some methods for the 'user' object: -class user_add(frontend.Method): +class user_add(crud.Add): 'Add a new user.' api.register(user_add) -class user_del(frontend.Method): +class user_del(crud.Del): 'Delete an existing user.' api.register(user_del) -class user_mod(frontend.Method): +class user_mod(crud.Mod): 'Edit an existing user.' api.register(user_mod) -class user_find(frontend.Method): +class user_find(crud.Find): 'Search the users.' api.register(user_find) +class user_show(crud.Get): + 'Examine an existing user.' +api.register(user_show) + # Register some properties for the 'user' object: #class user_givenname(frontend.Property): -- cgit From 0c3ebe0befa780485e108bfd85d05fbf6a7bc8e9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 25 Sep 2008 23:21:41 +0000 Subject: 367: Implementing basics of loading plugins out of tree --- ipalib/plugins/__init__.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/__init__.py b/ipalib/plugins/__init__.py index 91b56733..58db94ca 100644 --- a/ipalib/plugins/__init__.py +++ b/ipalib/plugins/__init__.py @@ -20,6 +20,3 @@ """ Sub-package containing all internal plugins. """ - -import example -import override -- cgit From afdc72103847fc27efd00f8cc97a7320909ff6a0 Mon Sep 17 00:00:00 2001 From: Martin Nagy Date: Mon, 29 Sep 2008 17:41:30 +0200 Subject: Add support for environment variables, change tests accordingly --- ipalib/plugins/example.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 7576d2a1..c565d678 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -57,6 +57,23 @@ class discover(frontend.Command): 'Discover IPA servers on network.' api.register(discover) +# Command to get the idea how plugins will interact with api.env +class envtest(frontend.Command): + 'Show current environment.' + def run(*args, **kw): + print "" + print "Environment variables:" + for var in api.env: + val = api.env[var] + if var is 'servers': + print "" + print " Servers:" + for item in api.env.servers: + print " %s" % item + print "" + else: + print " %s: %s" % (var, val) +api.register(envtest) # Register some methods for the 'user' object: class user_add(crud.Add): -- cgit From b965e558b5def14c6416beb36dc790cca96c3724 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 25 Sep 2008 23:53:53 -0400 Subject: Rebase XML-RPC client and server Fix error handling in server to return exceptions generated in library code --- ipalib/plugins/example.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index c565d678..c7d16160 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -26,7 +26,8 @@ from ipalib import frontend from ipalib import crud from ipalib.frontend import Param from ipalib import api - +from ipalib import servercore +import ldap class user(frontend.Object): 'User object' @@ -78,6 +79,8 @@ api.register(envtest) # Register some methods for the 'user' object: class user_add(crud.Add): 'Add a new user.' + def execute(self, *args, **kw): + return 1 api.register(user_add) class user_del(crud.Del): @@ -90,6 +93,10 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' + def execute(self, *args, **kw): + uid=args[0] + result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) + return result api.register(user_find) class user_show(crud.Get): -- cgit From 77e6c99f9d8e34e85add7671d89bf7698a4fe5c2 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 30 Sep 2008 00:48:53 -0400 Subject: Migrate to new source tree layoute --- ipalib/plugins/example.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index c7d16160..6113c117 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -21,12 +21,11 @@ Some example plugins. """ - from ipalib import frontend from ipalib import crud from ipalib.frontend import Param from ipalib import api -from ipalib import servercore +from ipa_server import servercore import ldap class user(frontend.Object): -- cgit From 7ee0ccd90d99609f8e85bf0e197ca5a747231fb8 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 30 Sep 2008 20:27:52 -0600 Subject: Fixed unit tests; changed example.py so it doesn't import servercore --- ipalib/plugins/example.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py index 6113c117..e4d7dc10 100644 --- a/ipalib/plugins/example.py +++ b/ipalib/plugins/example.py @@ -25,8 +25,6 @@ from ipalib import frontend from ipalib import crud from ipalib.frontend import Param from ipalib import api -from ipa_server import servercore -import ldap class user(frontend.Object): 'User object' -- cgit From af6653f6074e43fd6db83111c2b5b55b5b9b56e0 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 1 Oct 2008 15:50:04 -0600 Subject: Added skeleton for kerberos backend --- ipalib/plugins/b_kerberos.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 ipalib/plugins/b_kerberos.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_kerberos.py b/ipalib/plugins/b_kerberos.py new file mode 100644 index 00000000..4b3a9a5b --- /dev/null +++ b/ipalib/plugins/b_kerberos.py @@ -0,0 +1,34 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Kerberos backend. + +This wraps the python-kerberos and python-krbV bindings. +""" + +from ipalib import api +from ipalib.backend import Backend + +class krb(Backend): + """ + Kerberos backend plugin. + """ + +api.register(krb) -- cgit From cc93e45e1309d90e1a47c9bc73c785ffe630edfb Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 1 Oct 2008 15:53:21 -0600 Subject: Removed depreciated override.py module --- ipalib/plugins/override.py | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 ipalib/plugins/override.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/override.py b/ipalib/plugins/override.py deleted file mode 100644 index 29ec2509..00000000 --- a/ipalib/plugins/override.py +++ /dev/null @@ -1,33 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# Copyright (C) 2008 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; version 2 only -# -# 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" -An example of overriding a plugin. - -This example depends upon the order that the plugins/ modules are imported -in plugins/__init__.py, which will likely change in the near future. -""" - -from ipalib import api - -if 'user_mod' in api.register.Method: - base = api.register.Method.user_mod - class user_mod(base): - 'Example override, see ipalib/plugins/override.py' - api.register(user_mod, override=True) -- cgit From e963be1dda58494a80198a8d8a1cec5f2c898ca2 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 1 Oct 2008 15:56:04 -0600 Subject: Renamed plugins/example.py to plugins/f_user.py --- ipalib/plugins/example.py | 178 ---------------------------------------------- ipalib/plugins/f_user.py | 178 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 178 insertions(+), 178 deletions(-) delete mode 100644 ipalib/plugins/example.py create mode 100644 ipalib/plugins/f_user.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/example.py b/ipalib/plugins/example.py deleted file mode 100644 index e4d7dc10..00000000 --- a/ipalib/plugins/example.py +++ /dev/null @@ -1,178 +0,0 @@ -# Authors: -# Jason Gerard DeRose -# -# Copyright (C) 2008 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; version 2 only -# -# 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, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" -Some example plugins. -""" - -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param -from ipalib import api - -class user(frontend.Object): - 'User object' - takes_params = ( - 'givenname', - 'sn', - Param('uid', - primary_key=True, - default_from=lambda givenname, sn: givenname[0] + sn, - normalize=lambda value: value.lower(), - ), - Param('krbprincipalname', - default_from=lambda uid: '%s@EXAMPLE.COM' % uid, - ), - Param('homedirectory', - default_from=lambda uid: '/home/%s' % uid, - ) - ) -api.register(user) - - -# Hypothetical functional commands (not associated with any object): -class krbtest(frontend.Command): - 'Test your Kerberos ticket.' -api.register(krbtest) - -class discover(frontend.Command): - 'Discover IPA servers on network.' -api.register(discover) - -# Command to get the idea how plugins will interact with api.env -class envtest(frontend.Command): - 'Show current environment.' - def run(*args, **kw): - print "" - print "Environment variables:" - for var in api.env: - val = api.env[var] - if var is 'servers': - print "" - print " Servers:" - for item in api.env.servers: - print " %s" % item - print "" - else: - print " %s: %s" % (var, val) -api.register(envtest) - -# Register some methods for the 'user' object: -class user_add(crud.Add): - 'Add a new user.' - def execute(self, *args, **kw): - return 1 -api.register(user_add) - -class user_del(crud.Del): - 'Delete an existing user.' -api.register(user_del) - -class user_mod(crud.Mod): - 'Edit an existing user.' -api.register(user_mod) - -class user_find(crud.Find): - 'Search the users.' - def execute(self, *args, **kw): - uid=args[0] - result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) - return result -api.register(user_find) - -class user_show(crud.Get): - 'Examine an existing user.' -api.register(user_show) - - -# Register some properties for the 'user' object: -#class user_givenname(frontend.Property): -# 'User first name' -# required = True -#api.register(user_givenname) - -#class user_sn(frontend.Property): -# 'User last name' -# required = True -#api.register(user_sn) - -#class user_login(frontend.Property): -# 'User login' -# required = True -# default_from = frontend.DefaultFrom( -# lambda first, last: (first[0] + last).lower(), -# 'givenname', 'sn' -# ) -#api.register(user_login) - -#class user_initials(frontend.Property): -# 'User initials' -# required = True -# default_from = frontend.DefaultFrom( -# lambda first, last: first[0] + last[0], -# 'givenname', 'sn' -# ) -#api.register(user_initials) - - -# Register some methods for the 'group' object: -class group_add(frontend.Method): - 'Add a new group.' -api.register(group_add) - -class group_del(frontend.Method): - 'Delete an existing group.' -api.register(group_del) - -class group_mod(frontend.Method): - 'Edit an existing group.' -api.register(group_mod) - -class group_find(frontend.Method): - 'Search the groups.' -api.register(group_find) - - -# Register some methods for the 'service' object -class service_add(frontend.Method): - 'Add a new service.' -api.register(service_add) - -class service_del(frontend.Method): - 'Delete an existing service.' -api.register(service_del) - -class service_mod(frontend.Method): - 'Edit an existing service.' -api.register(service_mod) - -class service_find(frontend.Method): - 'Search the services.' -api.register(service_find) - - -# And to emphasis that the registration order doesn't matter, -# we'll register the objects last: -class group(frontend.Object): - 'Group object' -api.register(group) - -class service(frontend.Object): - 'Service object' -api.register(service) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py new file mode 100644 index 00000000..e4d7dc10 --- /dev/null +++ b/ipalib/plugins/f_user.py @@ -0,0 +1,178 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Some example plugins. +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api + +class user(frontend.Object): + 'User object' + takes_params = ( + 'givenname', + 'sn', + Param('uid', + primary_key=True, + default_from=lambda givenname, sn: givenname[0] + sn, + normalize=lambda value: value.lower(), + ), + Param('krbprincipalname', + default_from=lambda uid: '%s@EXAMPLE.COM' % uid, + ), + Param('homedirectory', + default_from=lambda uid: '/home/%s' % uid, + ) + ) +api.register(user) + + +# Hypothetical functional commands (not associated with any object): +class krbtest(frontend.Command): + 'Test your Kerberos ticket.' +api.register(krbtest) + +class discover(frontend.Command): + 'Discover IPA servers on network.' +api.register(discover) + +# Command to get the idea how plugins will interact with api.env +class envtest(frontend.Command): + 'Show current environment.' + def run(*args, **kw): + print "" + print "Environment variables:" + for var in api.env: + val = api.env[var] + if var is 'servers': + print "" + print " Servers:" + for item in api.env.servers: + print " %s" % item + print "" + else: + print " %s: %s" % (var, val) +api.register(envtest) + +# Register some methods for the 'user' object: +class user_add(crud.Add): + 'Add a new user.' + def execute(self, *args, **kw): + return 1 +api.register(user_add) + +class user_del(crud.Del): + 'Delete an existing user.' +api.register(user_del) + +class user_mod(crud.Mod): + 'Edit an existing user.' +api.register(user_mod) + +class user_find(crud.Find): + 'Search the users.' + def execute(self, *args, **kw): + uid=args[0] + result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) + return result +api.register(user_find) + +class user_show(crud.Get): + 'Examine an existing user.' +api.register(user_show) + + +# Register some properties for the 'user' object: +#class user_givenname(frontend.Property): +# 'User first name' +# required = True +#api.register(user_givenname) + +#class user_sn(frontend.Property): +# 'User last name' +# required = True +#api.register(user_sn) + +#class user_login(frontend.Property): +# 'User login' +# required = True +# default_from = frontend.DefaultFrom( +# lambda first, last: (first[0] + last).lower(), +# 'givenname', 'sn' +# ) +#api.register(user_login) + +#class user_initials(frontend.Property): +# 'User initials' +# required = True +# default_from = frontend.DefaultFrom( +# lambda first, last: first[0] + last[0], +# 'givenname', 'sn' +# ) +#api.register(user_initials) + + +# Register some methods for the 'group' object: +class group_add(frontend.Method): + 'Add a new group.' +api.register(group_add) + +class group_del(frontend.Method): + 'Delete an existing group.' +api.register(group_del) + +class group_mod(frontend.Method): + 'Edit an existing group.' +api.register(group_mod) + +class group_find(frontend.Method): + 'Search the groups.' +api.register(group_find) + + +# Register some methods for the 'service' object +class service_add(frontend.Method): + 'Add a new service.' +api.register(service_add) + +class service_del(frontend.Method): + 'Delete an existing service.' +api.register(service_del) + +class service_mod(frontend.Method): + 'Edit an existing service.' +api.register(service_mod) + +class service_find(frontend.Method): + 'Search the services.' +api.register(service_find) + + +# And to emphasis that the registration order doesn't matter, +# we'll register the objects last: +class group(frontend.Object): + 'Group object' +api.register(group) + +class service(frontend.Object): + 'Service object' +api.register(service) -- cgit From c846c7d91f0654dc4f52bedb053a79166c8d6adf Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 1 Oct 2008 16:10:41 -0600 Subject: Removed the everything except the envtest command and the user related plugins from f_user.py --- ipalib/plugins/f_user.py | 135 ++++++++++------------------------------------- 1 file changed, 28 insertions(+), 107 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index e4d7dc10..a482a963 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Some example plugins. +Frontend plugins for user (Identity). """ from ipalib import frontend @@ -26,34 +26,6 @@ from ipalib import crud from ipalib.frontend import Param from ipalib import api -class user(frontend.Object): - 'User object' - takes_params = ( - 'givenname', - 'sn', - Param('uid', - primary_key=True, - default_from=lambda givenname, sn: givenname[0] + sn, - normalize=lambda value: value.lower(), - ), - Param('krbprincipalname', - default_from=lambda uid: '%s@EXAMPLE.COM' % uid, - ), - Param('homedirectory', - default_from=lambda uid: '/home/%s' % uid, - ) - ) -api.register(user) - - -# Hypothetical functional commands (not associated with any object): -class krbtest(frontend.Command): - 'Test your Kerberos ticket.' -api.register(krbtest) - -class discover(frontend.Command): - 'Discover IPA servers on network.' -api.register(discover) # Command to get the idea how plugins will interact with api.env class envtest(frontend.Command): @@ -73,21 +45,46 @@ class envtest(frontend.Command): print " %s: %s" % (var, val) api.register(envtest) -# Register some methods for the 'user' object: + +class user(frontend.Object): + """ + User object. + """ + takes_params = ( + 'givenname', + 'sn', + Param('uid', + primary_key=True, + default_from=lambda givenname, sn: givenname[0] + sn, + normalize=lambda value: value.lower(), + ), + Param('krbprincipalname', + default_from=lambda uid: '%s@EXAMPLE.COM' % uid, + ), + Param('homedirectory', + default_from=lambda uid: '/home/%s' % uid, + ) + ) +api.register(user) + + class user_add(crud.Add): 'Add a new user.' def execute(self, *args, **kw): return 1 api.register(user_add) + class user_del(crud.Del): 'Delete an existing user.' api.register(user_del) + class user_mod(crud.Mod): 'Edit an existing user.' api.register(user_mod) + class user_find(crud.Find): 'Search the users.' def execute(self, *args, **kw): @@ -96,83 +93,7 @@ class user_find(crud.Find): return result api.register(user_find) + class user_show(crud.Get): 'Examine an existing user.' api.register(user_show) - - -# Register some properties for the 'user' object: -#class user_givenname(frontend.Property): -# 'User first name' -# required = True -#api.register(user_givenname) - -#class user_sn(frontend.Property): -# 'User last name' -# required = True -#api.register(user_sn) - -#class user_login(frontend.Property): -# 'User login' -# required = True -# default_from = frontend.DefaultFrom( -# lambda first, last: (first[0] + last).lower(), -# 'givenname', 'sn' -# ) -#api.register(user_login) - -#class user_initials(frontend.Property): -# 'User initials' -# required = True -# default_from = frontend.DefaultFrom( -# lambda first, last: first[0] + last[0], -# 'givenname', 'sn' -# ) -#api.register(user_initials) - - -# Register some methods for the 'group' object: -class group_add(frontend.Method): - 'Add a new group.' -api.register(group_add) - -class group_del(frontend.Method): - 'Delete an existing group.' -api.register(group_del) - -class group_mod(frontend.Method): - 'Edit an existing group.' -api.register(group_mod) - -class group_find(frontend.Method): - 'Search the groups.' -api.register(group_find) - - -# Register some methods for the 'service' object -class service_add(frontend.Method): - 'Add a new service.' -api.register(service_add) - -class service_del(frontend.Method): - 'Delete an existing service.' -api.register(service_del) - -class service_mod(frontend.Method): - 'Edit an existing service.' -api.register(service_mod) - -class service_find(frontend.Method): - 'Search the services.' -api.register(service_find) - - -# And to emphasis that the registration order doesn't matter, -# we'll register the objects last: -class group(frontend.Object): - 'Group object' -api.register(group) - -class service(frontend.Object): - 'Service object' -api.register(service) -- cgit From 2507b7c6741330eafacce63deca630073fb536fd Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 1 Oct 2008 16:17:02 -0600 Subject: Clarified docstrings in */plugins/__init__.py; renamed ipa_server/plugins/ipa_ldap.py to b_ldap.py --- ipalib/plugins/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/__init__.py b/ipalib/plugins/__init__.py index 58db94ca..544429ef 100644 --- a/ipalib/plugins/__init__.py +++ b/ipalib/plugins/__init__.py @@ -18,5 +18,8 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Sub-package containing all internal plugins. +Sub-package containing all core plugins. + +By convention, modules with frontend plugins are named f_*.py and modules +with backend plugins are named b_*.py. """ -- cgit From 0e137110c7f3c543faf9ec4cc7917d6aa81f02a6 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 2 Oct 2008 16:12:19 -0600 Subject: Started on skeleton for xmlrcp client/server --- ipalib/plugins/b_xmlrpc.py | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 ipalib/plugins/b_xmlrpc.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py new file mode 100644 index 00000000..afe76505 --- /dev/null +++ b/ipalib/plugins/b_xmlrpc.py @@ -0,0 +1,39 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +XML-RPC client plugin. + +Lightwieght XML-RPC client using Python standard library xmlrpclib. +""" + +import xmlrpclib +from ipalib.backend import Backend +from ipalib import api + +class xmlrpc(Backend): + """ + Kerberos backend plugin. + """ + + def get_client(self): + # FIXME: The server uri should come from self.api.env.server_uri + return xmlrpclib.ServerProxy('http://localhost:8080', allow_none=True) + +api.register(xmlrpc) -- cgit From 6000b6b5c62181d25783b6d45adb2ed6f3928480 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 2 Oct 2008 17:02:24 -0600 Subject: Implemented basic Command.forward() method --- ipalib/plugins/f_user.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index a482a963..29f0f8a0 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -87,10 +87,10 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' - def execute(self, *args, **kw): - uid=args[0] - result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) - return result +# def execute(self, *args, **kw): +# uid=args[0] +# result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) +# return result api.register(user_find) -- cgit From 3ffbaac64cc3a9ab704c707112f59e041986576c Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 2 Oct 2008 19:42:06 -0600 Subject: Backend.xmlrpc and simple-server.py now use the xmlrpc_marshal() and xmlrpc_unmarshal() functions respectively --- ipalib/plugins/b_xmlrpc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index afe76505..61935f01 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -25,6 +25,7 @@ Lightwieght XML-RPC client using Python standard library xmlrpclib. import xmlrpclib from ipalib.backend import Backend +from ipalib.util import xmlrpc_marshal from ipalib import api class xmlrpc(Backend): @@ -36,4 +37,13 @@ class xmlrpc(Backend): # FIXME: The server uri should come from self.api.env.server_uri return xmlrpclib.ServerProxy('http://localhost:8080', allow_none=True) + def forward_call(self, name, *args, **kw): + """ + Forward a call over XML-RPC to an IPA server. + """ + client = self.get_client() + command = getattr(client, name) + params = xmlrpc_marshal(*args, **kw) + return command(*params) + api.register(xmlrpc) -- cgit From 7e4b0a072e69351496010d7b2151c9b434c8fdb0 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Sat, 4 Oct 2008 01:50:59 -0400 Subject: Implement user-find and user-add backend functions so they work over XML-RPC Change port to 8880 to not conflict with a running IPA v1 instance Encode incoming values from unicode as utf-8 before sending to LDAP --- ipalib/plugins/b_xmlrpc.py | 3 +- ipalib/plugins/f_user.py | 91 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 87 insertions(+), 7 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 61935f01..f8dacf5d 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -35,7 +35,7 @@ class xmlrpc(Backend): def get_client(self): # FIXME: The server uri should come from self.api.env.server_uri - return xmlrpclib.ServerProxy('http://localhost:8080', allow_none=True) + return xmlrpclib.ServerProxy('http://localhost:8888', allow_none=True) def forward_call(self, name, *args, **kw): """ @@ -45,5 +45,6 @@ class xmlrpc(Backend): command = getattr(client, name) params = xmlrpc_marshal(*args, **kw) return command(*params) +# return command(*args, **kw) api.register(xmlrpc) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 29f0f8a0..320666aa 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -25,7 +25,10 @@ from ipalib import frontend from ipalib import crud from ipalib.frontend import Param from ipalib import api - +from ipa_server import servercore +from ipa_server import ipaldap +import ldap +from ipa_server.context import context # Command to get the idea how plugins will interact with api.env class envtest(frontend.Command): @@ -71,7 +74,79 @@ api.register(user) class user_add(crud.Add): 'Add a new user.' def execute(self, *args, **kw): - return 1 + """args[0] = uid of the user to add + kw{container} is the location in the DIT to add the user, not + required + kw otherwise contains all the attributes + """ + # FIXME: ug, really? + if not kw.get('container'): + user_container = servercore.DefaultUserContainer + else: + user_container = kw['container'] + del kw['container'] + + user = kw + + if not isinstance(user, dict): + # FIXME, need proper error + raise SyntaxError + + user['uid'] = args[0] + + # dn is set here, not by the user + try: + del user['dn'] + except KeyError: + pass + + # No need to set empty fields, and they can cause issues when they + # get to LDAP, like: + # TypeError: ('expected a string in the list', None) + for k in user.keys(): + if not user[k] or len(user[k]) == 0 or (isinstance(user[k],list) and len(user[k]) == 1 and '' in user[k]): + del user[k] + + dn="uid=%s,%s,%s" % (ldap.dn.escape_dn_chars(user['uid']), + user_container,servercore.basedn) + + entry = ipaldap.Entry(dn) + + # Let us add in some missing attributes + # FIXME, get config +# if user.get('homedirectory') is None: +# user['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), user.get('uid')) +# user['homedirectory'] = user['homedirectory'].replace('//', '/') +# user['homedirectory'] = user['homedirectory'].rstrip('/') +# if user.get('loginshell') is None: +# user['loginshell'] = config.get('ipadefaultloginshell') + if user.get('gecos') is None: + user['gecos'] = user['uid'] + + # FIXME: add to default group + user['gidNumber'] = "500" + + if user.get('krbprincipalname') is None: + user['krbprincipalname'] = "%s@%s" % (user.get('uid'), self.realm) + + # FIXME. This is a hack so we can request separate First and Last + # name in the GUI. + if user.get('cn') is None: + user['cn'] = "%s %s" % (user.get('givenname'), + user.get('sn')) + + # some required objectclasses + # FIXME + # entry.setValues('objectClass', (config.get('ipauserobjectclasses'))) + entry.setValues('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'inetUser', 'posixAccount', 'krbPrincipalAux']) + + # fill in our new entry with everything sent by the user + for u in user: + entry.setValues(u, user[u]) + + result = context.conn.getConn().addEntry(entry) + return result + api.register(user_add) @@ -87,10 +162,14 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' -# def execute(self, *args, **kw): -# uid=args[0] -# result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) -# return result + def execute(self, *args, **kw): + uid=args[0] + result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) + return result + def forward(self, *args, **kw): + result = super(crud.Find, self).forward(*args, **kw) + for a in result: + print a, ": ", res[a] api.register(user_find) -- cgit From cb795fa14bc2798fd8f1c6e2b87d19432e3f84a1 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Sat, 4 Oct 2008 05:17:11 -0400 Subject: Add group plugin, routine to get cn=ipaconfig --- ipalib/plugins/f_group.py | 117 ++++++++++++++++++++++++++++++++++++++++++++++ ipalib/plugins/f_user.py | 41 ++++++++++------ 2 files changed, 145 insertions(+), 13 deletions(-) create mode 100644 ipalib/plugins/f_group.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py new file mode 100644 index 00000000..36cecc33 --- /dev/null +++ b/ipalib/plugins/f_group.py @@ -0,0 +1,117 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for group (Identity). +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api +from ipa_server import servercore +from ipa_server import ipaldap +import ldap +from ipa_server.context import context + + +class group(frontend.Object): + """ + Group object. + """ + takes_params = ( + 'description', + Param('cn', + primary_key=True, + normalize=lambda value: value.lower(), + ) + ) +api.register(group) + + +class group_add(crud.Add): + 'Add a new group.' + def execute(self, *args, **kw): + """args[0] = uid of the group to add + kw{container} is the location in the DIT to add the group, not + required + kw otherwise contains all the attributes + """ + # FIXME: ug, really? + if not kw.get('container'): + group_container = servercore.DefaultGroupContainer + else: + group_container = kw['container'] + del kw['container'] + + group = kw + + group['cn'] = args[0] + + # Get our configuration + config = servercore.get_ipa_config() + + dn="cn=%s,%s,%s" % (ldap.dn.escape_dn_chars(group['cn']), + group_container,servercore.basedn) + + entry = ipaldap.Entry(dn) + + # some required objectclasses + entry.setValues('objectClass', (config.get('ipagroupobjectclasses'))) + + # No need to explicitly set gidNumber. The dna_plugin will do this + # for us if the value isn't provided by the user. + + # fill in our new entry with everything sent by the user + for g in group: + entry.setValues(g, group[g]) + + result = context.conn.getConn().addEntry(entry) + return result + + +api.register(group_add) + + +class group_del(crud.Del): + 'Delete an existing group.' +api.register(group_del) + + +class group_mod(crud.Mod): + 'Edit an existing group.' +api.register(group_mod) + + +class group_find(crud.Find): + 'Search the groups.' + def execute(self, *args, **kw): + cn=args[0] + result = servercore.get_sub_entry(servercore.basedn, "cn=%s" % cn, ["*"]) + return result + def forward(self, *args, **kw): + result = super(crud.Find, self).forward(*args, **kw) + for a in result: + print a, ": ", result[a] +api.register(group_find) + + +class group_show(crud.Get): + 'Examine an existing group.' +api.register(group_show) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 320666aa..0e62b833 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -112,19 +112,35 @@ class user_add(crud.Add): entry = ipaldap.Entry(dn) + # Get our configuration + config = servercore.get_ipa_config() + # Let us add in some missing attributes - # FIXME, get config -# if user.get('homedirectory') is None: -# user['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), user.get('uid')) -# user['homedirectory'] = user['homedirectory'].replace('//', '/') -# user['homedirectory'] = user['homedirectory'].rstrip('/') -# if user.get('loginshell') is None: -# user['loginshell'] = config.get('ipadefaultloginshell') + if user.get('homedirectory') is None: + user['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), user.get('uid')) + user['homedirectory'] = user['homedirectory'].replace('//', '/') + user['homedirectory'] = user['homedirectory'].rstrip('/') + if user.get('loginshell') is None: + user['loginshell'] = config.get('ipadefaultloginshell') if user.get('gecos') is None: user['gecos'] = user['uid'] - # FIXME: add to default group - user['gidNumber'] = "500" + # If uidnumber is blank the the FDS dna_plugin will automatically + # assign the next value. So we don't have to do anything with it. + + group_dn="cn=%s,%s,%s" % (config.get('ipadefaultprimarygroup'), servercore.DefaultGroupContainer, servercore.basedn) + try: + default_group = servercore.get_entry_by_dn(group_dn, ['dn','gidNumber']) + if default_group: + user['gidnumber'] = default_group.get('gidnumber') +# except ipaerror.exception_for(ipaerror.LDAP_DATABASE_ERROR), e: +# raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, message=None, nested_exception=e.detail) +# except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): +# # Fake an LDAP error so we can return something useful to the user +# raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND, "The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup')) + except Exception, e: + # FIXME + raise e if user.get('krbprincipalname') is None: user['krbprincipalname'] = "%s@%s" % (user.get('uid'), self.realm) @@ -136,9 +152,8 @@ class user_add(crud.Add): user.get('sn')) # some required objectclasses - # FIXME - # entry.setValues('objectClass', (config.get('ipauserobjectclasses'))) - entry.setValues('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'inetUser', 'posixAccount', 'krbPrincipalAux']) + entry.setValues('objectClass', (config.get('ipauserobjectclasses'))) + # entry.setValues('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'inetUser', 'posixAccount', 'krbPrincipalAux']) # fill in our new entry with everything sent by the user for u in user: @@ -169,7 +184,7 @@ class user_find(crud.Find): def forward(self, *args, **kw): result = super(crud.Find, self).forward(*args, **kw) for a in result: - print a, ": ", res[a] + print a, ": ", result[a] api.register(user_find) -- cgit From 69bc5ad77adecaf7d8fde4a6578c3d2f3ef355df Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 7 Oct 2008 02:10:15 -0400 Subject: Add some more supporting functions Do a little bit more error handling and checking --- ipalib/plugins/b_xmlrpc.py | 8 ++++++-- ipalib/plugins/f_group.py | 3 +-- ipalib/plugins/f_user.py | 14 ++++++++++++-- 3 files changed, 19 insertions(+), 6 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index f8dacf5d..d7cbd856 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -24,6 +24,7 @@ Lightwieght XML-RPC client using Python standard library xmlrpclib. """ import xmlrpclib +import socket from ipalib.backend import Backend from ipalib.util import xmlrpc_marshal from ipalib import api @@ -44,7 +45,10 @@ class xmlrpc(Backend): client = self.get_client() command = getattr(client, name) params = xmlrpc_marshal(*args, **kw) - return command(*params) -# return command(*args, **kw) + try: + return command(*params) + except socket.error, e: + print e[1] + return False api.register(xmlrpc) diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index 36cecc33..c5a37e72 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -28,7 +28,6 @@ from ipalib import api from ipa_server import servercore from ipa_server import ipaldap import ldap -from ipa_server.context import context class group(frontend.Object): @@ -82,7 +81,7 @@ class group_add(crud.Add): for g in group: entry.setValues(g, group[g]) - result = context.conn.getConn().addEntry(entry) + result = servercore.add_entry(entry) return result diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 0e62b833..49b6a370 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -28,7 +28,6 @@ from ipalib import api from ipa_server import servercore from ipa_server import ipaldap import ldap -from ipa_server.context import context # Command to get the idea how plugins will interact with api.env class envtest(frontend.Command): @@ -94,6 +93,13 @@ class user_add(crud.Add): user['uid'] = args[0] + if not servercore.is_user_unique(user['uid']): + # FIXME, specific error + raise SyntaxError("user already exists") + if servercore.uid_too_long(user['uid']): + # FIXME, specific error + raise SyntaxError("uid is too long") + # dn is set here, not by the user try: del user['dn'] @@ -159,8 +165,12 @@ class user_add(crud.Add): for u in user: entry.setValues(u, user[u]) - result = context.conn.getConn().addEntry(entry) + result = servercore.add_entry(entry) return result + def forward(self, *args, **kw): + result = super(crud.Add, self).forward(*args, **kw) + if result != False: + print result api.register(user_add) -- cgit From e012e860b472bcb5a00a089e73113fb6989fde20 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 7 Oct 2008 04:31:22 -0400 Subject: Implement user-mod --- ipalib/plugins/f_user.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 49b6a370..0b424d35 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -170,7 +170,7 @@ class user_add(crud.Add): def forward(self, *args, **kw): result = super(crud.Add, self).forward(*args, **kw) if result != False: - print result + print "User %s added" % args[0] api.register(user_add) @@ -182,6 +182,25 @@ api.register(user_del) class user_mod(crud.Mod): 'Edit an existing user.' + def execute(self, *args, **kw): + uid=args[0] + result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) + + user = kw + dn = result.get('dn') + del result['dn'] + entry = ipaldap.Entry((dn, servercore.convert_scalar_values(result))) + + for u in user: + entry.setValues(u, user[u]) + + result = servercore.update_entry(entry.toDict()) + + return result + def forward(self, *args, **kw): + result = super(crud.Mod, self).forward(*args, **kw) + if result != False: + print "User %s modified" % args[0] api.register(user_mod) -- cgit From db9d8dd3e0924bb9c7f9c89a56e6b6057dabc710 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 7 Oct 2008 06:15:34 -0400 Subject: Implement a real user_find and move existing user_find to user_show --- ipalib/plugins/f_user.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 0b424d35..e560d03c 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -208,15 +208,33 @@ class user_find(crud.Find): 'Search the users.' def execute(self, *args, **kw): uid=args[0] - result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) + result = servercore.find_users(uid, ["*"]) return result def forward(self, *args, **kw): - result = super(crud.Find, self).forward(*args, **kw) - for a in result: - print a, ": ", result[a] + users = super(crud.Find, self).forward(*args, **kw) + counter = users[0] + users = users[1:] + if counter == 0: + print "No entries found for", args[0] + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for u in users: + for a in u.keys(): + print "%s: %s" % (a, u[a]) api.register(user_find) class user_show(crud.Get): 'Examine an existing user.' + def execute(self, *args, **kw): + uid=args[0] + result = servercore.get_user_by_uid(uid, ["*"]) + return result + def forward(self, *args, **kw): + result = super(crud.Get, self).forward(*args, **kw) + for a in result: + print a, ": ", result[a] api.register(user_show) -- cgit From 4a68c719f03c176bc63a96007c089d0ac7ae5fc1 Mon Sep 17 00:00:00 2001 From: Martin Nagy Date: Fri, 3 Oct 2008 17:08:37 +0200 Subject: Implement config file reading --- ipalib/plugins/f_user.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 29f0f8a0..150d48ea 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -35,10 +35,10 @@ class envtest(frontend.Command): print "Environment variables:" for var in api.env: val = api.env[var] - if var is 'servers': + if var is 'server': print "" print " Servers:" - for item in api.env.servers: + for item in api.env.server: print " %s" % item print "" else: -- cgit From b2b5b904bcc1ab96d5efb992d5630505022d0ecb Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 7 Oct 2008 20:07:16 -0600 Subject: Made package-level docstrings more consistent so they read better in generated documentation --- ipalib/plugins/b_kerberos.py | 2 +- ipalib/plugins/b_xmlrpc.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_kerberos.py b/ipalib/plugins/b_kerberos.py index 4b3a9a5b..cc820497 100644 --- a/ipalib/plugins/b_kerberos.py +++ b/ipalib/plugins/b_kerberos.py @@ -18,7 +18,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -Kerberos backend. +Backend plugin for Kerberos. This wraps the python-kerberos and python-krbV bindings. """ diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index d7cbd856..feb87556 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -18,9 +18,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """ -XML-RPC client plugin. +Backend plugin for XML-RPC client. -Lightwieght XML-RPC client using Python standard library xmlrpclib. +This provides a lightwieght XML-RPC client using Python standard library +``xmlrpclib`` module. """ import xmlrpclib -- cgit From 672c07566df8d838b46edb6b80ba73ade2a27d55 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 7 Oct 2008 23:38:00 -0400 Subject: Implement user-del rename is_user_unique() to user_exists() --- ipalib/plugins/f_user.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index b006c24b..f87ddea1 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -93,7 +93,7 @@ class user_add(crud.Add): user['uid'] = args[0] - if not servercore.is_user_unique(user['uid']): + if servercore.user_exists(user['uid']): # FIXME, specific error raise SyntaxError("user already exists") if servercore.uid_too_long(user['uid']): @@ -177,6 +177,31 @@ api.register(user_add) class user_del(crud.Del): 'Delete an existing user.' + def execute(self, *args, **kw): + """args[0] = uid of the user to remove + + Delete a user. Not to be confused with inactivate_user. This + makes the entry go away completely. + + uid is the uid of the user to delete + + The memberOf plugin handles removing the user from any other + groups. + """ + uid = args[0] + if uid == "admin": + raise ipaerror.gen_exception(ipaerror.INPUT_ADMIN_REQUIRED) +# logging.info("IPA: delete_user '%s'" % uid) + user = servercore.get_user_by_uid(uid, ['dn', 'uid']) + if not user: + # FIXME, specific error + raise SyntaxError("user doesn't exist") + + return servercore.delete_entry(user['dn']) + def forward(self, *args, **kw): + result = super(crud.Del, self).forward(*args, **kw) + if result != False: + print "User %s removed" % args[0] api.register(user_del) -- cgit From 83bb41faebc0a61269f2869e9123166254fff5b3 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 8 Oct 2008 23:31:49 -0400 Subject: Mechanism to convert from xmlrpclib.Fault to an IPAError exception Include slew of new exceptions, not all of which are used yet --- ipalib/plugins/b_xmlrpc.py | 3 +++ ipalib/plugins/f_user.py | 48 ++++++++++++++++++++++------------------------ 2 files changed, 26 insertions(+), 25 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index feb87556..442afebf 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -29,6 +29,7 @@ import socket from ipalib.backend import Backend from ipalib.util import xmlrpc_marshal from ipalib import api +from ipalib import errors class xmlrpc(Backend): """ @@ -51,5 +52,7 @@ class xmlrpc(Backend): except socket.error, e: print e[1] return False + except xmlrpclib.Fault, e: + raise errors.convertFault(e) api.register(xmlrpc) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index f87ddea1..8a1c3045 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -25,6 +25,7 @@ from ipalib import frontend from ipalib import crud from ipalib.frontend import Param from ipalib import api +from ipalib import errors from ipa_server import servercore from ipa_server import ipaldap import ldap @@ -32,7 +33,7 @@ import ldap # Command to get the idea how plugins will interact with api.env class envtest(frontend.Command): 'Show current environment.' - def run(*args, **kw): + def run(self, *args, **kw): print "" print "Environment variables:" for var in api.env: @@ -87,18 +88,12 @@ class user_add(crud.Add): user = kw - if not isinstance(user, dict): - # FIXME, need proper error - raise SyntaxError - user['uid'] = args[0] if servercore.user_exists(user['uid']): - # FIXME, specific error - raise SyntaxError("user already exists") + raise errors.Duplicate("user already exists") if servercore.uid_too_long(user['uid']): - # FIXME, specific error - raise SyntaxError("uid is too long") + raise errors.UsernameTooLong # dn is set here, not by the user try: @@ -139,17 +134,15 @@ class user_add(crud.Add): default_group = servercore.get_entry_by_dn(group_dn, ['dn','gidNumber']) if default_group: user['gidnumber'] = default_group.get('gidnumber') -# except ipaerror.exception_for(ipaerror.LDAP_DATABASE_ERROR), e: -# raise ipaerror.gen_exception(ipaerror.LDAP_DATABASE_ERROR, message=None, nested_exception=e.detail) -# except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND): -# # Fake an LDAP error so we can return something useful to the user -# raise ipaerror.gen_exception(ipaerror.LDAP_NOT_FOUND, "The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup')) + except errors.NotFound: + # Fake an LDAP error so we can return something useful to the user + raise ipalib.NotFound, "The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup') except Exception, e: - # FIXME + # catch everything else raise e if user.get('krbprincipalname') is None: - user['krbprincipalname'] = "%s@%s" % (user.get('uid'), self.realm) + user['krbprincipalname'] = "%s@%s" % (user.get('uid'), servercore.realm) # FIXME. This is a hack so we can request separate First and Last # name in the GUI. @@ -169,7 +162,7 @@ class user_add(crud.Add): return result def forward(self, *args, **kw): result = super(crud.Add, self).forward(*args, **kw) - if result != False: + if result: print "User %s added" % args[0] api.register(user_add) @@ -190,17 +183,18 @@ class user_del(crud.Del): """ uid = args[0] if uid == "admin": - raise ipaerror.gen_exception(ipaerror.INPUT_ADMIN_REQUIRED) + # FIXME: do we still want a "special" user? + raise SyntaxError("admin required") +# raise ipaerror.gen_exception(ipaerror.INPUT_ADMIN_REQUIRED) # logging.info("IPA: delete_user '%s'" % uid) user = servercore.get_user_by_uid(uid, ['dn', 'uid']) if not user: - # FIXME, specific error - raise SyntaxError("user doesn't exist") + raise errors.NotFound return servercore.delete_entry(user['dn']) def forward(self, *args, **kw): result = super(crud.Del, self).forward(*args, **kw) - if result != False: + if result: print "User %s removed" % args[0] api.register(user_del) @@ -224,7 +218,7 @@ class user_mod(crud.Mod): return result def forward(self, *args, **kw): result = super(crud.Mod, self).forward(*args, **kw) - if result != False: + if result: print "User %s modified" % args[0] api.register(user_mod) @@ -259,7 +253,11 @@ class user_show(crud.Get): result = servercore.get_user_by_uid(uid, ["*"]) return result def forward(self, *args, **kw): - result = super(crud.Get, self).forward(*args, **kw) - for a in result: - print a, ": ", result[a] + try: + result = super(crud.Get, self).forward(*args, **kw) + if not result: return + for a in result: + print a, ": ", result[a] + except errors.NotFound: + print "User %s not found" % args[0] api.register(user_show) -- cgit From 8a97b3e8a8f437cd99cc7cabbc719368b0247983 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 9 Oct 2008 23:11:03 -0400 Subject: Implement group-del --- ipalib/plugins/b_xmlrpc.py | 9 +++++++-- ipalib/plugins/f_group.py | 48 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 442afebf..da76aa2b 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -51,8 +51,13 @@ class xmlrpc(Backend): return command(*params) except socket.error, e: print e[1] - return False except xmlrpclib.Fault, e: - raise errors.convertFault(e) + err = errors.convertFault(e) + code = getattr(err,'faultCode',None) + if code: + print "%s: %s" % (code, getattr(err,'__doc__','')) + else: + raise err + return False api.register(xmlrpc) diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index c5a37e72..fd56b3ff 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -27,6 +27,7 @@ from ipalib.frontend import Param from ipalib import api from ipa_server import servercore from ipa_server import ipaldap +from ipa_server import ipautil import ldap @@ -83,13 +84,49 @@ class group_add(crud.Add): result = servercore.add_entry(entry) return result - - + def forward(self, *args, **kw): + result = super(crud.Add, self).forward(*args, **kw) + if result: + print "Group %s added" % args[0] api.register(group_add) class group_del(crud.Del): 'Delete an existing group.' + def execute(self, *args, **kw): + """args[0] = dn of the group to remove + + Delete a group + + The memberOf plugin handles removing the group from any other + groups. + """ + group_dn = args[0] + + group = servercore.get_entry_by_dn(group_dn, ['dn', 'cn']) + if group is None: + raise errors.NotFound +# logging.info("IPA: delete_group '%s'" % group_dn) + + # We have 2 special groups, don't allow them to be removed + # FIXME +# if "admins" in group.get('cn') or "editors" in group.get('cn'): +# raise ipaerror.gen_exception(ipaerror.CONFIG_REQUIRED_GROUPS) + + # Don't allow the default user group to be removed + config=servercore.get_ipa_config() + default_group = servercore.get_entry_by_cn(config.get('ipadefaultprimarygroup'), None) + if group_dn == default_group.get('dn'): + raise errors.DefaultGroup + + return servercore.delete_entry(group_dn) + def forward(self, *args, **kw): + group = self.api.Command['group_show'](ipautil.utf8_encode_value(args[0])) + if not group: + print "nothing found" + return False + a = group.get('dn') + result = super(crud.Del, self).forward(a) api.register(group_del) @@ -113,4 +150,11 @@ api.register(group_find) class group_show(crud.Get): 'Examine an existing group.' + def execute(self, *args, **kw): + cn=args[0] + result = servercore.get_sub_entry(servercore.basedn, "cn=%s" % cn, ["*"]) + return result + def forward(self, *args, **kw): + result = super(crud.Get, self).forward(*args, **kw) + return result api.register(group_show) -- cgit From 5d2a99925d4b8f8bb39dfbf4ae797d9845366109 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 9 Oct 2008 23:32:28 -0400 Subject: Implement group-mod --- ipalib/plugins/f_group.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index fd56b3ff..eeb18c5c 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -132,6 +132,25 @@ api.register(group_del) class group_mod(crud.Mod): 'Edit an existing group.' + def execute(self, *args, **kw): + group_cn=args[0] + result = servercore.get_entry_by_cn(group_cn, ["*"]) + + group = kw + dn = result.get('dn') + del result['dn'] + entry = ipaldap.Entry((dn, servercore.convert_scalar_values(result))) + + for g in group: + entry.setValues(g, group[g]) + + result = servercore.update_entry(entry.toDict()) + + return result + def forward(self, *args, **kw): + result = super(crud.Mod, self).forward(*args, **kw) + if result: + print "Group %s modified" % args[0] api.register(group_mod) -- cgit From dbe49423ab16ed9ad01166feee22b68b7b05c725 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 10 Oct 2008 03:36:39 -0400 Subject: Start service principal plugin --- ipalib/plugins/f_service.py | 155 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 ipalib/plugins/f_service.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py new file mode 100644 index 00000000..0db1171c --- /dev/null +++ b/ipalib/plugins/f_service.py @@ -0,0 +1,155 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for service (Identity). +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api +from ipalib import errors +from ipalib import ipa_types +from ipa_server import servercore +from ipa_server import ipaldap +import ldap + +class service(frontend.Object): + """ + Service object. + """ + takes_params = ( + Param('principal', primary_key=True), + ) +api.register(service) + + +class service_add(crud.Add): + 'Add a new service.' + """ + my_params = ( + Param('force', type=ipa_types.Bool(), default=False), + ) + def get_options(self): + for param in self.my_params: + yield param + """ + def execute(self, *args, **kw): + """args[0] = service principal to add + kw{force} determines whether we continue on errors + """ + force = kw.get('force', False) + + principal = args[0] + + # Break down the principal into its component parts, which may or + # may not include the realm. + sp = principal.split('/') + if len(sp) != 2: + raise errors.MalformedServicePrincipal + service = sp[0] + + sr = sp[1].split('@') + if len(sr) == 1: + hostname = sr[0].lower() + realm = servercore.realm + elif len(sr) == 2: + hostname = sr[0].lower() + realm = sr[1] + else: + raise MalformedServicePrincipal + + """ + FIXME once DNS client is done + if not force: + fqdn = hostname + "." + rs = dnsclient.query(fqdn, dnsclient.DNS_C_IN, dnsclient.DNS_T_A) + if len(rs) == 0: + logging.debug("IPA: DNS A record lookup failed for '%s'" % hostname) + raise ipaerror.gen_exception(ipaerror.INPUT_NOT_DNS_A_RECORD) + else: + logging.debug("IPA: found %d records for '%s'" % (len(rs), hostname)) + """ + + service_container = servercore.DefaultServiceContainer + + # At some point we'll support multiple realms + if (realm != servercore.realm): + raise errors.RealmMismatch + + # Put the principal back together again + princ_name = service + "/" + hostname + "@" + realm + + dn = "krbprincipalname=%s,%s,%s" % (ldap.dn.escape_dn_chars(princ_name), + service_container,servercore.basedn) + entry = ipaldap.Entry(dn) + + entry.setValues('objectClass', 'krbPrincipal', 'krbPrincipalAux', 'krbTicketPolicyAux') + entry.setValues('krbprincipalname', princ_name) + + result = servercore.add_entry(entry) + return result + def forward(self, *args, **kw): + result = super(crud.Add, self).forward(*args, **kw) + if result: + print "Service %s added" % args[0] +api.register(service_add) + + +class service_del(crud.Del): + 'Delete an existing service.' + def execute(self, *args, **kw): + """args[0] = princial to remove + + Delete a service principal. + + principal is the full DN of the entry to delete. + + This should be called with much care. + """ + principal = args[0] + return False + def forward(self, *args, **kw): + result = super(crud.Del, self).forward(*args, **kw) + if result: + print "Service %s removed" % args[0] +api.register(service_del) + + +class service_mod(crud.Mod): + 'Edit an existing service.' +api.register(service_mod) + + +class service_find(crud.Find): + 'Search the existing services.' +api.register(service_find) + + +class service_show(crud.Get): + 'Examine an existing service.' + def execute(self, *args, **kw): + filter = "(&(objectclass=krbPrincipalAux)(!(objectClass=person))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))(&(|(krbprincipalname=%s))))" % args[0] + result = servercore.get_sub_entry(servercore.basedn, filter, ["*"]) + return result + def forward(self, *args, **kw): + result = super(crud.Get, self).forward(*args, **kw) + return result +api.register(service_show) -- cgit From 42cdca3e8340c9aae721d582a522b7991ea38050 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 10 Oct 2008 03:40:52 -0400 Subject: Use new options handler --- ipalib/plugins/f_service.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index 0db1171c..baed5233 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -43,14 +43,9 @@ api.register(service) class service_add(crud.Add): 'Add a new service.' - """ - my_params = ( - Param('force', type=ipa_types.Bool(), default=False), + takes_options = ( + Param('force?', type=ipa_types.Bool(), default=False, doc='Force a service principal name'), ) - def get_options(self): - for param in self.my_params: - yield param - """ def execute(self, *args, **kw): """args[0] = service principal to add kw{force} determines whether we continue on errors -- cgit From 75bad44c27bff471c03ddc86283506f53f47520c Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 10 Oct 2008 05:23:00 -0400 Subject: Enable the verbose flag to pass thru xmlrpc --- ipalib/plugins/b_xmlrpc.py | 6 +++--- ipalib/plugins/f_user.py | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index da76aa2b..618f8385 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -36,15 +36,15 @@ class xmlrpc(Backend): Kerberos backend plugin. """ - def get_client(self): + def get_client(self, verbose=False): # FIXME: The server uri should come from self.api.env.server_uri - return xmlrpclib.ServerProxy('http://localhost:8888', allow_none=True) + return xmlrpclib.ServerProxy('http://localhost:8888', verbose=verbose) def forward_call(self, name, *args, **kw): """ Forward a call over XML-RPC to an IPA server. """ - client = self.get_client() + client = self.get_client(verbose=api.env.get('verbose', False)) command = getattr(client, name) params = xmlrpc_marshal(*args, **kw) try: diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 8a1c3045..9dbc93cb 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -231,6 +231,8 @@ class user_find(crud.Find): return result def forward(self, *args, **kw): users = super(crud.Find, self).forward(*args, **kw) + if not users: + return counter = users[0] users = users[1:] if counter == 0: -- cgit From 39ad5ccffa60e42904b7f3d2f7a60fef5977f089 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Sat, 11 Oct 2008 00:49:05 -0400 Subject: Stub out delegations Add ACI class --- ipalib/plugins/f_delegation.py | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 ipalib/plugins/f_delegation.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_delegation.py b/ipalib/plugins/f_delegation.py new file mode 100644 index 00000000..762df1db --- /dev/null +++ b/ipalib/plugins/f_delegation.py @@ -0,0 +1,68 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for delegations. +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api +from ipalib import errors +from ipa_server import servercore +from ipa_server import ipaldap +import ldap + +class delegation(frontend.Object): + """ + Delegation object. + """ + takes_params = ( + 'attributes', + 'source', + 'target', + Param('name', primary_key=True) + ) +api.register(user) + + +class delegation_add(crud.Add): + 'Add a new delegation.' +api.register(delegation_add) + + +class delegation_del(crud.Del): + 'Delete an existing delegation.' +api.register(delegation_del) + + +class delegation_mod(crud.Mod): + 'Edit an existing delegation.' +api.register(delegation_mod) + + +class delegation_find(crud.Find): + 'Search for a delegation.' +api.register(delegation_find) + + +class delegation_show(crud.Get): + 'Examine an existing delegation.' +api.register(delegation_show) -- cgit From 250734aea539f0c49c21cb1cdc0310fcbf19f65c Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 10 Oct 2008 14:38:09 -0400 Subject: Fix syntax error --- ipalib/plugins/f_delegation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_delegation.py b/ipalib/plugins/f_delegation.py index 762df1db..1fb2b4f9 100644 --- a/ipalib/plugins/f_delegation.py +++ b/ipalib/plugins/f_delegation.py @@ -40,7 +40,7 @@ class delegation(frontend.Object): 'target', Param('name', primary_key=True) ) -api.register(user) +api.register(delegation) class delegation_add(crud.Add): -- cgit From 0ebaad646207c8819097124d0e483251d9d5d47d Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 13 Oct 2008 14:59:48 -0400 Subject: Do a more specific search for the user --- ipalib/plugins/f_user.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 9dbc93cb..573a2a43 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -203,7 +203,9 @@ class user_mod(crud.Mod): 'Edit an existing user.' def execute(self, *args, **kw): uid=args[0] - result = servercore.get_sub_entry(servercore.basedn, "uid=%s" % uid, ["*"]) + + # Get the existing user entry + result = servercore.get_sub_entry("cn=accounts," + servercore.basedn, "uid=%s" % uid, ["*"]) user = kw dn = result.get('dn') -- cgit From fc9f057792cf91a2a2536719ac7f1eb836b1c4a1 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 13 Oct 2008 15:01:08 -0400 Subject: Initial implementation of password policy --- ipalib/plugins/f_pwpolicy.py | 100 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 ipalib/plugins/f_pwpolicy.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_pwpolicy.py b/ipalib/plugins/f_pwpolicy.py new file mode 100644 index 00000000..9e5aa3d0 --- /dev/null +++ b/ipalib/plugins/f_pwpolicy.py @@ -0,0 +1,100 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for password policy. +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api +from ipalib import errors +from ipalib import ipa_types +from ipa_server import servercore +from ipa_server import ipaldap +import ldap + + +class pwpolicy_mod(frontend.Command): + 'Edit an existing user.' + # FIXME, switch to more human-readable names at some point + takes_options = ( + Param('krbmaxpwdlife?', type=ipa_types.Int(), doc='Max. Password Lifetime (days)'), + Param('krbminpwdlife?', type=ipa_types.Int(), doc='Min. Password Lifetime (hours)'), + Param('krbpwdhistorylength?', type=ipa_types.Int(), doc='Password History Size'), + Param('krbpwdmindiffchars?', type=ipa_types.Int(), doc='Min. Number of Character Classes'), + Param('krbpwdminlength?', type=ipa_types.Int(), doc='Min. Length of Password'), + ) + def execute(self, *args, **kw): + # Get the existing policy entry + oldpolicy = servercore.get_entry_by_cn("accounts", None) + + # Convert the existing policy into an entry object + dn = oldpolicy.get('dn') + del oldpolicy['dn'] + entry = ipaldap.Entry((dn, servercore.convert_scalar_values(oldpolicy))) + + # FIXME: if the user passed no options should we return something + # more than No modifications to be performed? + + policy = kw + + # The LDAP routines want strings, not ints, so convert a few + # things. Otherwise it sees a string -> int conversion as a change. + for k in policy.iterkeys(): + if k.startswith("krb", 0, 3): + policy[k] = str(policy[k]) + + # Convert hours and days to seconds + if policy.get('krbmaxpwdlife'): + policy['krbmaxpwdlife'] = str(int(policy.get('krbmaxpwdlife')) * 86400) + if policy.get('krbminpwdlife'): + policy['krbminpwdlife'] = str(int(policy.get('krbminpwdlife')) * 3600) + # Update the values passed-in + for p in policy: + # Values need to be strings, not integers + entry.setValues(p, str(policy[p])) + + result = servercore.update_entry(entry.toDict()) + + return result + def forward(self, *args, **kw): + result = super(pwpolicy_mod, self).forward(*args, **kw) + if result: + print "Policy modified" +api.register(pwpolicy_mod) + + +class pwpolicy_show(frontend.Command): + 'Retrieve current password policy' + def execute(self, *args, **kw): + policy = servercore.get_entry_by_cn("accounts", None) + + # convert some values for display purposes + policy['krbmaxpwdlife'] = str(int(policy.get('krbmaxpwdlife')) / 86400) + policy['krbminpwdlife'] = str(int(policy.get('krbminpwdlife')) / 3600) + + return policy + + def forward(self, *args, **kw): + result = super(pwpolicy_show, self).forward(*args, **kw) + if not result: return + print result +api.register(pwpolicy_show) -- cgit From 19465318cebed2a2ae844d33e69728c1eb9fd7d6 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 13 Oct 2008 15:17:31 -0400 Subject: Fix up a comment --- ipalib/plugins/f_pwpolicy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_pwpolicy.py b/ipalib/plugins/f_pwpolicy.py index 9e5aa3d0..36e232dc 100644 --- a/ipalib/plugins/f_pwpolicy.py +++ b/ipalib/plugins/f_pwpolicy.py @@ -33,7 +33,7 @@ import ldap class pwpolicy_mod(frontend.Command): - 'Edit an existing user.' + 'Edit existing password policy.' # FIXME, switch to more human-readable names at some point takes_options = ( Param('krbmaxpwdlife?', type=ipa_types.Int(), doc='Max. Password Lifetime (days)'), -- cgit From 6d2705b363e95b5bd692b695cdcbbfcbca6d12b9 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 13 Oct 2008 17:17:00 -0400 Subject: Implement user lock and unlock --- ipalib/plugins/f_user.py | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 573a2a43..ff459b3d 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -26,6 +26,7 @@ from ipalib import crud from ipalib.frontend import Param from ipalib import api from ipalib import errors +from ipalib import ipa_types from ipa_server import servercore from ipa_server import ipaldap import ldap @@ -136,7 +137,7 @@ class user_add(crud.Add): user['gidnumber'] = default_group.get('gidnumber') except errors.NotFound: # Fake an LDAP error so we can return something useful to the user - raise ipalib.NotFound, "The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup') + raise errors.NotFound, "The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup') except Exception, e: # catch everything else raise e @@ -265,3 +266,34 @@ class user_show(crud.Get): except errors.NotFound: print "User %s not found" % args[0] api.register(user_show) + +class user_lock(frontend.Command): + 'Lock a user account.' + takes_args = ( + Param('uid', primary_key=True), + ) + def execute(self, *args, **kw): + uid = args[0] + user = servercore.get_user_by_uid(uid, ['dn', 'uid']) + return servercore.mark_entry_inactive(user['dn']) + def forward(self, *args, **kw): + result = super(user_lock, self).forward(*args, **kw) + if result: + print "User locked" +api.register(user_lock) + +class user_unlock(frontend.Command): + 'Unlock a user account.' + takes_args = ( + Param('uid', primary_key=True), + ) + def execute(self, *args, **kw): + uid = args[0] + user = servercore.get_user_by_uid(uid, ['dn', 'uid']) + return servercore.mark_entry_active(user['dn']) + def forward(self, *args, **kw): + result = super(user_unlock, self).forward(*args, **kw) + if result: + print "User unlocked" +api.register(user_unlock) + -- cgit From b6dcd183a66ca6056f9d23637de0f12aee15efcc Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 13 Oct 2008 20:31:10 -0600 Subject: CLI now maps Param.cli_name to Param.name --- ipalib/plugins/f_user.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index ff459b3d..22fb8a27 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -55,9 +55,10 @@ class user(frontend.Object): User object. """ takes_params = ( - 'givenname', - 'sn', + Param('givenname', cli_name='firstname'), + Param('sn', cli_name='lastname'), Param('uid', + cli_name='user', primary_key=True, default_from=lambda givenname, sn: givenname[0] + sn, normalize=lambda value: value.lower(), @@ -78,7 +79,7 @@ class user_add(crud.Add): """args[0] = uid of the user to add kw{container} is the location in the DIT to add the user, not required - kw otherwise contains all the attributes + kw otherwise contains all the attributes """ # FIXME: ug, really? if not kw.get('container'): @@ -296,4 +297,3 @@ class user_unlock(frontend.Command): if result: print "User unlocked" api.register(user_unlock) - -- cgit From 1480224724864cb7cf34c9be755b905c61f885b9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 14 Oct 2008 01:45:30 -0600 Subject: Started roughing out user_add() using api.Backend.ldap; added Command.output_for_cli() to take care of formatting print output --- ipalib/plugins/f_user.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 22fb8a27..571f6fa8 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -75,12 +75,26 @@ api.register(user) class user_add(crud.Add): 'Add a new user.' - def execute(self, *args, **kw): - """args[0] = uid of the user to add - kw{container} is the location in the DIT to add the user, not - required - kw otherwise contains all the attributes + + def execute(self, uid, **kw): + """ + Execute the user-add operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry as it will be created in LDAP. + + :param uid: The login name of the user being added. + :param kw: Keyword arguments for the other LDAP attributes. """ + assert 'uid' not in kw + assert 'dn' not in kw + kw['uid'] = uid + kw['dn'] = self.api.Backend.ldap.get_user_dn(uid) + + return kw + # FIXME: ug, really? if not kw.get('container'): user_container = servercore.DefaultUserContainer @@ -162,10 +176,6 @@ class user_add(crud.Add): result = servercore.add_entry(entry) return result - def forward(self, *args, **kw): - result = super(crud.Add, self).forward(*args, **kw) - if result: - print "User %s added" % args[0] api.register(user_add) -- cgit From 9788800aa41146551baee6d36314a20203fd9d20 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 14 Oct 2008 02:23:56 -0600 Subject: More work on making user-add use Backend.ldap --- ipalib/plugins/f_user.py | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 571f6fa8..b35a1122 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -55,20 +55,36 @@ class user(frontend.Object): User object. """ takes_params = ( - Param('givenname', cli_name='firstname'), - Param('sn', cli_name='lastname'), + Param('givenname', + cli_name='first', + doc='User first name', + ), + Param('sn', + cli_name='last', + doc='User last name', + ), Param('uid', cli_name='user', primary_key=True, default_from=lambda givenname, sn: givenname[0] + sn, normalize=lambda value: value.lower(), ), - Param('krbprincipalname', - default_from=lambda uid: '%s@EXAMPLE.COM' % uid, + Param('gecos', + doc='GECOS field', + default_from=lambda uid: uid, ), Param('homedirectory', + cli_name='home', + doc='Path of user home directory', default_from=lambda uid: '/home/%s' % uid, - ) + ), + Param('shell', + default=u'/bin/sh', + doc='Login shell', + ), + Param('krbprincipalname?', cli_name='principal', + default_from=lambda uid: '%s@EXAMPLE.COM' % uid, + ), ) api.register(user) @@ -90,21 +106,11 @@ class user_add(crud.Add): """ assert 'uid' not in kw assert 'dn' not in kw + ldap = self.api.Backend.ldap kw['uid'] = uid - kw['dn'] = self.api.Backend.ldap.get_user_dn(uid) - - return kw - - # FIXME: ug, really? - if not kw.get('container'): - user_container = servercore.DefaultUserContainer - else: - user_container = kw['container'] - del kw['container'] - - user = kw + kw['dn'] = ldap.get_user_dn(uid) + return ldap.create(**kw) - user['uid'] = args[0] if servercore.user_exists(user['uid']): raise errors.Duplicate("user already exists") -- cgit From ff88652a405c7fd9236a9b1d80dd8955a9ca056d Mon Sep 17 00:00:00 2001 From: Martin Nagy Date: Tue, 14 Oct 2008 21:22:44 +0200 Subject: Convert string values to boolean when generating environment --- ipalib/plugins/f_user.py | 1 + 1 file changed, 1 insertion(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index b35a1122..b2c191fb 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -47,6 +47,7 @@ class envtest(frontend.Command): print "" else: print " %s: %s" % (var, val) + return {} api.register(envtest) -- cgit From 30664cde88b70f478d75a768426db5f655c5f867 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 14 Oct 2008 17:46:36 -0400 Subject: Move some functionality from user-add to the backend ldap create function --- ipalib/plugins/f_user.py | 73 +++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 50 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index b35a1122..03bc9aa8 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -69,16 +69,17 @@ class user(frontend.Object): default_from=lambda givenname, sn: givenname[0] + sn, normalize=lambda value: value.lower(), ), - Param('gecos', + Param('gecos?', doc='GECOS field', default_from=lambda uid: uid, ), - Param('homedirectory', + Param('homedirectory?', cli_name='home', doc='Path of user home directory', default_from=lambda uid: '/home/%s' % uid, ), - Param('shell', + Param('loginshell?', + cli_name='shell', default=u'/bin/sh', doc='Login shell', ), @@ -109,44 +110,22 @@ class user_add(crud.Add): ldap = self.api.Backend.ldap kw['uid'] = uid kw['dn'] = ldap.get_user_dn(uid) - return ldap.create(**kw) - - if servercore.user_exists(user['uid']): - raise errors.Duplicate("user already exists") - if servercore.uid_too_long(user['uid']): + if servercore.uid_too_long(kw['uid']): raise errors.UsernameTooLong - # dn is set here, not by the user - try: - del user['dn'] - except KeyError: - pass - - # No need to set empty fields, and they can cause issues when they - # get to LDAP, like: - # TypeError: ('expected a string in the list', None) - for k in user.keys(): - if not user[k] or len(user[k]) == 0 or (isinstance(user[k],list) and len(user[k]) == 1 and '' in user[k]): - del user[k] - - dn="uid=%s,%s,%s" % (ldap.dn.escape_dn_chars(user['uid']), - user_container,servercore.basedn) - - entry = ipaldap.Entry(dn) - # Get our configuration config = servercore.get_ipa_config() # Let us add in some missing attributes - if user.get('homedirectory') is None: - user['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), user.get('uid')) - user['homedirectory'] = user['homedirectory'].replace('//', '/') - user['homedirectory'] = user['homedirectory'].rstrip('/') - if user.get('loginshell') is None: - user['loginshell'] = config.get('ipadefaultloginshell') - if user.get('gecos') is None: - user['gecos'] = user['uid'] + if kw.get('homedirectory') is None: + kw['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), kw.get('uid')) + kw['homedirectory'] = kw['homedirectory'].replace('//', '/') + kw['homedirectory'] = kw['homedirectory'].rstrip('/') + if kw.get('loginshell') is None: + kw['loginshell'] = config.get('ipadefaultloginshell') + if kw.get('gecos') is None: + kw['gecos'] = kw['uid'] # If uidnumber is blank the the FDS dna_plugin will automatically # assign the next value. So we don't have to do anything with it. @@ -155,33 +134,27 @@ class user_add(crud.Add): try: default_group = servercore.get_entry_by_dn(group_dn, ['dn','gidNumber']) if default_group: - user['gidnumber'] = default_group.get('gidnumber') + kw['gidnumber'] = default_group.get('gidnumber') except errors.NotFound: - # Fake an LDAP error so we can return something useful to the user - raise errors.NotFound, "The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup') + # Fake an LDAP error so we can return something useful to the kw + raise errors.NotFound, "The default group for new kws, '%s', cannot be found." % config.get('ipadefaultprimarygroup') except Exception, e: # catch everything else raise e - if user.get('krbprincipalname') is None: - user['krbprincipalname'] = "%s@%s" % (user.get('uid'), servercore.realm) + if kw.get('krbprincipalname') is None: + kw['krbprincipalname'] = "%s@%s" % (kw.get('uid'), servercore.realm) # FIXME. This is a hack so we can request separate First and Last # name in the GUI. - if user.get('cn') is None: - user['cn'] = "%s %s" % (user.get('givenname'), - user.get('sn')) + if kw.get('cn') is None: + kw['cn'] = "%s %s" % (kw.get('givenname'), + kw.get('sn')) # some required objectclasses - entry.setValues('objectClass', (config.get('ipauserobjectclasses'))) - # entry.setValues('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'inetUser', 'posixAccount', 'krbPrincipalAux']) - - # fill in our new entry with everything sent by the user - for u in user: - entry.setValues(u, user[u]) + kw['objectClass'] = config.get('ipauserobjectclasses') - result = servercore.add_entry(entry) - return result + return ldap.create(**kw) api.register(user_add) -- cgit From 1c3f81852cb8337e2305f968be5bd8165997d27e Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 14 Oct 2008 17:46:36 -0400 Subject: Move some functionality from user-add to the backend ldap create function --- ipalib/plugins/f_user.py | 73 +++++++++++++++--------------------------------- 1 file changed, 23 insertions(+), 50 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index b2c191fb..e3ecd223 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -70,16 +70,17 @@ class user(frontend.Object): default_from=lambda givenname, sn: givenname[0] + sn, normalize=lambda value: value.lower(), ), - Param('gecos', + Param('gecos?', doc='GECOS field', default_from=lambda uid: uid, ), - Param('homedirectory', + Param('homedirectory?', cli_name='home', doc='Path of user home directory', default_from=lambda uid: '/home/%s' % uid, ), - Param('shell', + Param('loginshell?', + cli_name='shell', default=u'/bin/sh', doc='Login shell', ), @@ -110,44 +111,22 @@ class user_add(crud.Add): ldap = self.api.Backend.ldap kw['uid'] = uid kw['dn'] = ldap.get_user_dn(uid) - return ldap.create(**kw) - - if servercore.user_exists(user['uid']): - raise errors.Duplicate("user already exists") - if servercore.uid_too_long(user['uid']): + if servercore.uid_too_long(kw['uid']): raise errors.UsernameTooLong - # dn is set here, not by the user - try: - del user['dn'] - except KeyError: - pass - - # No need to set empty fields, and they can cause issues when they - # get to LDAP, like: - # TypeError: ('expected a string in the list', None) - for k in user.keys(): - if not user[k] or len(user[k]) == 0 or (isinstance(user[k],list) and len(user[k]) == 1 and '' in user[k]): - del user[k] - - dn="uid=%s,%s,%s" % (ldap.dn.escape_dn_chars(user['uid']), - user_container,servercore.basedn) - - entry = ipaldap.Entry(dn) - # Get our configuration config = servercore.get_ipa_config() # Let us add in some missing attributes - if user.get('homedirectory') is None: - user['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), user.get('uid')) - user['homedirectory'] = user['homedirectory'].replace('//', '/') - user['homedirectory'] = user['homedirectory'].rstrip('/') - if user.get('loginshell') is None: - user['loginshell'] = config.get('ipadefaultloginshell') - if user.get('gecos') is None: - user['gecos'] = user['uid'] + if kw.get('homedirectory') is None: + kw['homedirectory'] = '%s/%s' % (config.get('ipahomesrootdir'), kw.get('uid')) + kw['homedirectory'] = kw['homedirectory'].replace('//', '/') + kw['homedirectory'] = kw['homedirectory'].rstrip('/') + if kw.get('loginshell') is None: + kw['loginshell'] = config.get('ipadefaultloginshell') + if kw.get('gecos') is None: + kw['gecos'] = kw['uid'] # If uidnumber is blank the the FDS dna_plugin will automatically # assign the next value. So we don't have to do anything with it. @@ -156,33 +135,27 @@ class user_add(crud.Add): try: default_group = servercore.get_entry_by_dn(group_dn, ['dn','gidNumber']) if default_group: - user['gidnumber'] = default_group.get('gidnumber') + kw['gidnumber'] = default_group.get('gidnumber') except errors.NotFound: - # Fake an LDAP error so we can return something useful to the user - raise errors.NotFound, "The default group for new users, '%s', cannot be found." % config.get('ipadefaultprimarygroup') + # Fake an LDAP error so we can return something useful to the kw + raise errors.NotFound, "The default group for new kws, '%s', cannot be found." % config.get('ipadefaultprimarygroup') except Exception, e: # catch everything else raise e - if user.get('krbprincipalname') is None: - user['krbprincipalname'] = "%s@%s" % (user.get('uid'), servercore.realm) + if kw.get('krbprincipalname') is None: + kw['krbprincipalname'] = "%s@%s" % (kw.get('uid'), servercore.realm) # FIXME. This is a hack so we can request separate First and Last # name in the GUI. - if user.get('cn') is None: - user['cn'] = "%s %s" % (user.get('givenname'), - user.get('sn')) + if kw.get('cn') is None: + kw['cn'] = "%s %s" % (kw.get('givenname'), + kw.get('sn')) # some required objectclasses - entry.setValues('objectClass', (config.get('ipauserobjectclasses'))) - # entry.setValues('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'inetUser', 'posixAccount', 'krbPrincipalAux']) - - # fill in our new entry with everything sent by the user - for u in user: - entry.setValues(u, user[u]) + kw['objectClass'] = config.get('ipauserobjectclasses') - result = servercore.add_entry(entry) - return result + return ldap.create(**kw) api.register(user_add) -- cgit From cfc8450efd92dc0fb6648e97b27416c67625adfb Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 14 Oct 2008 22:22:01 -0400 Subject: Port user-show to new CrudBackend framework --- ipalib/plugins/b_xmlrpc.py | 2 +- ipalib/plugins/f_user.py | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 618f8385..db2af1ab 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -58,6 +58,6 @@ class xmlrpc(Backend): print "%s: %s" % (code, getattr(err,'__doc__','')) else: raise err - return False + return {} api.register(xmlrpc) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index e3ecd223..1e79c4b8 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -110,7 +110,7 @@ class user_add(crud.Add): assert 'dn' not in kw ldap = self.api.Backend.ldap kw['uid'] = uid - kw['dn'] = ldap.get_user_dn(uid) + kw['dn'] = ldap.make_user_dn(uid) if servercore.uid_too_long(kw['uid']): raise errors.UsernameTooLong @@ -244,18 +244,23 @@ api.register(user_find) class user_show(crud.Get): 'Examine an existing user.' - def execute(self, *args, **kw): - uid=args[0] - result = servercore.get_user_by_uid(uid, ["*"]) - return result - def forward(self, *args, **kw): - try: - result = super(crud.Get, self).forward(*args, **kw) - if not result: return - for a in result: - print a, ": ", result[a] - except errors.NotFound: - print "User %s not found" % args[0] + def execute(self, uid, **kw): + """ + Execute the user-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param uid: The login name of the user to retrieve. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, ["*"], "posixAccount") + # FIXME: should kw contain the list of attributes? + return ldap.retrieve(dn) + api.register(user_show) class user_lock(frontend.Command): -- cgit From f7c044495ae22d372fb064dbacfe0ff027c437a7 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 14 Oct 2008 22:48:57 -0400 Subject: Port user_del to CrudBackend Override output_for_cli() to generate nicer output --- ipalib/plugins/f_user.py | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 1e79c4b8..79c45735 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -157,23 +157,30 @@ class user_add(crud.Add): return ldap.create(**kw) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "User added" + api.register(user_add) class user_del(crud.Del): 'Delete an existing user.' - def execute(self, *args, **kw): - """args[0] = uid of the user to remove - - Delete a user. Not to be confused with inactivate_user. This + def execute(self, uid, **kw): + """Delete a user. Not to be confused with inactivate_user. This makes the entry go away completely. uid is the uid of the user to delete The memberOf plugin handles removing the user from any other groups. + + :param uid: The login name of the user being added. + :param kw: Not used. """ - uid = args[0] if uid == "admin": # FIXME: do we still want a "special" user? raise SyntaxError("admin required") @@ -183,11 +190,16 @@ class user_del(crud.Del): if not user: raise errors.NotFound - return servercore.delete_entry(user['dn']) - def forward(self, *args, **kw): - result = super(crud.Del, self).forward(*args, **kw) - if result: - print "User %s removed" % args[0] + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, ["*"], "posixAccount") + return ldap.delete(dn) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "User deleted" + api.register(user_del) -- cgit From 789a248daa71d5d1377e0dc9f0cd3afe107d4f2a Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 15 Oct 2008 09:58:29 -0400 Subject: Port user-mod to use ldap update() method --- ipalib/plugins/f_user.py | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 79c45735..e95ee3b2 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -205,27 +205,31 @@ api.register(user_del) class user_mod(crud.Mod): 'Edit an existing user.' - def execute(self, *args, **kw): - uid=args[0] + def execute(self, uid, **kw): + """ + Execute the user-mod operation. - # Get the existing user entry - result = servercore.get_sub_entry("cn=accounts," + servercore.basedn, "uid=%s" % uid, ["*"]) + The dn should not be passed as a keyword argument as it is constructed + by this method. - user = kw - dn = result.get('dn') - del result['dn'] - entry = ipaldap.Entry((dn, servercore.convert_scalar_values(result))) + Returns the entry - for u in user: - entry.setValues(u, user[u]) + :param uid: The login name of the user to retrieve. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'uid' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, "posixAccount") + return ldap.update(dn, **kw) - result = servercore.update_entry(entry.toDict()) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "User updated" - return result - def forward(self, *args, **kw): - result = super(crud.Mod, self).forward(*args, **kw) - if result: - print "User %s modified" % args[0] api.register(user_mod) @@ -269,7 +273,7 @@ class user_show(crud.Get): :param kw: Not used. """ ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid, ["*"], "posixAccount") + dn = ldap.find_entry_dn("uid", uid, "posixAccount") # FIXME: should kw contain the list of attributes? return ldap.retrieve(dn) -- cgit From 3268b65ae0dfc7ffdeba685e8e2515a437bf092e Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 15 Oct 2008 16:11:34 -0400 Subject: Initial implementation of a generic search routine. --- ipalib/plugins/f_user.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index a1078fe7..c2bb7b6f 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -237,11 +237,10 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' def execute(self, *args, **kw): - uid=args[0] - result = servercore.find_users(uid, ["*"]) - return result - def forward(self, *args, **kw): - users = super(crud.Find, self).forward(*args, **kw) + ldap = self.api.Backend.ldap + kw['uid'] = args[0] + return ldap.search(**kw) + def output_for_cli(self, users): if not users: return counter = users[0] -- cgit From 14a33d461960b4183ac25a83a8ef9f375fd75d49 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 15 Oct 2008 16:50:46 -0400 Subject: Fix some remaining merge issues and don't use forward() in user-*lock() --- ipalib/plugins/f_user.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index c2bb7b6f..ed88ef9f 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -154,8 +154,6 @@ class user_add(crud.Add): # some required objectclasses kw['objectClass'] = config.get('ipauserobjectclasses') -<<<<<<< HEAD:ipalib/plugins/f_user.py -======= return ldap.create(**kw) def output_for_cli(self, ret): @@ -288,9 +286,8 @@ class user_lock(frontend.Command): uid = args[0] user = servercore.get_user_by_uid(uid, ['dn', 'uid']) return servercore.mark_entry_inactive(user['dn']) - def forward(self, *args, **kw): - result = super(user_lock, self).forward(*args, **kw) - if result: + def output_for_cli(self, ret): + if ret: print "User locked" api.register(user_lock) @@ -303,8 +300,7 @@ class user_unlock(frontend.Command): uid = args[0] user = servercore.get_user_by_uid(uid, ['dn', 'uid']) return servercore.mark_entry_active(user['dn']) - def forward(self, *args, **kw): - result = super(user_unlock, self).forward(*args, **kw) - if result: + def output_for_cli(self, ret): + if ret: print "User unlocked" api.register(user_unlock) -- cgit From 1a8317ff7471214811d39ab846d402dc22a03779 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 15 Oct 2008 17:46:01 -0400 Subject: Port group-add to use LDAP backend Have create and update return the record that was just added/modified --- ipalib/plugins/f_group.py | 57 ++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index eeb18c5c..a07d314b 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -38,6 +38,7 @@ class group(frontend.Object): takes_params = ( 'description', Param('cn', + cli_name='name', primary_key=True, normalize=lambda value: value.lower(), ) @@ -47,47 +48,43 @@ api.register(group) class group_add(crud.Add): 'Add a new group.' - def execute(self, *args, **kw): - """args[0] = uid of the group to add - kw{container} is the location in the DIT to add the group, not - required - kw otherwise contains all the attributes + + def execute(self, cn, **kw): """ - # FIXME: ug, really? - if not kw.get('container'): - group_container = servercore.DefaultGroupContainer - else: - group_container = kw['container'] - del kw['container'] + Execute the group-add operation. - group = kw + The dn should not be passed as a keyword argument as it is constructed + by this method. - group['cn'] = args[0] + Returns the entry as it will be created in LDAP. - # Get our configuration - config = servercore.get_ipa_config() + No need to explicitly set gidNumber. The dna_plugin will do this + for us if the value isn't provided by the caller. - dn="cn=%s,%s,%s" % (ldap.dn.escape_dn_chars(group['cn']), - group_container,servercore.basedn) + :param cn: The name of the group being added. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + kw['cn'] = cn + kw['dn'] = ldap.make_group_dn(cn) - entry = ipaldap.Entry(dn) + # Get our configuration + config = servercore.get_ipa_config() # some required objectclasses - entry.setValues('objectClass', (config.get('ipagroupobjectclasses'))) + kw['objectClass'] = config.get('ipagroupobjectclasses') - # No need to explicitly set gidNumber. The dna_plugin will do this - # for us if the value isn't provided by the user. + return ldap.create(**kw) - # fill in our new entry with everything sent by the user - for g in group: - entry.setValues(g, group[g]) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Group added" - result = servercore.add_entry(entry) - return result - def forward(self, *args, **kw): - result = super(crud.Add, self).forward(*args, **kw) - if result: - print "Group %s added" % args[0] api.register(group_add) -- cgit From 12f1e7fdf75b001ed2b73525a242feb15b272d51 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 16 Oct 2008 10:32:20 -0400 Subject: Remove all references to ipa_server.* from user plugin --- ipalib/plugins/f_user.py | 64 +++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 34 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index ed88ef9f..9fec1bd4 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -27,9 +27,6 @@ from ipalib.frontend import Param from ipalib import api from ipalib import errors from ipalib import ipa_types -from ipa_server import servercore -from ipa_server import ipaldap -import ldap # Command to get the idea how plugins will interact with api.env class envtest(frontend.Command): @@ -112,11 +109,12 @@ class user_add(crud.Add): kw['uid'] = uid kw['dn'] = ldap.make_user_dn(uid) - if servercore.uid_too_long(kw['uid']): - raise errors.UsernameTooLong + # FIXME: enforce this elsewhere +# if servercore.uid_too_long(kw['uid']): +# raise errors.UsernameTooLong # Get our configuration - config = servercore.get_ipa_config() + config = ldap.get_ipa_config() # Let us add in some missing attributes if kw.get('homedirectory') is None: @@ -131,20 +129,21 @@ class user_add(crud.Add): # If uidnumber is blank the the FDS dna_plugin will automatically # assign the next value. So we don't have to do anything with it. - group_dn="cn=%s,%s,%s" % (config.get('ipadefaultprimarygroup'), servercore.DefaultGroupContainer, servercore.basedn) - try: - default_group = servercore.get_entry_by_dn(group_dn, ['dn','gidNumber']) - if default_group: - kw['gidnumber'] = default_group.get('gidnumber') - except errors.NotFound: - # Fake an LDAP error so we can return something useful to the kw - raise errors.NotFound, "The default group for new kws, '%s', cannot be found." % config.get('ipadefaultprimarygroup') - except Exception, e: - # catch everything else - raise e + if not kw.get('gidnumber'): + try: + group_dn = ldap.find_entry_dn("cn", config.get('ipadefaultprimarygroup')) + default_group = ldap.retrieve(group_dn, ['dn','gidNumber']) + if default_group: + kw['gidnumber'] = default_group.get('gidnumber') + except errors.NotFound: + # Fake an LDAP error so we can return something useful to the kw + raise errors.NotFound, "The default group for new kws, '%s', cannot be found." % config.get('ipadefaultprimarygroup') + except Exception, e: + # catch everything else + raise e if kw.get('krbprincipalname') is None: - kw['krbprincipalname'] = "%s@%s" % (kw.get('uid'), servercore.realm) + kw['krbprincipalname'] = "%s@%s" % (kw.get('uid'), self.api.env.realm) # FIXME. This is a hack so we can request separate First and Last # name in the GUI. @@ -185,12 +184,9 @@ class user_del(crud.Del): raise SyntaxError("admin required") # raise ipaerror.gen_exception(ipaerror.INPUT_ADMIN_REQUIRED) # logging.info("IPA: delete_user '%s'" % uid) - user = servercore.get_user_by_uid(uid, ['dn', 'uid']) - if not user: - raise errors.NotFound ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid, ["*"], "posixAccount") + dn = ldap.find_entry_dn("uid", uid, "posixAccount") return ldap.delete(dn) def output_for_cli(self, ret): """ @@ -234,9 +230,9 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' - def execute(self, *args, **kw): + def execute(self, uid, **kw): ldap = self.api.Backend.ldap - kw['uid'] = args[0] + kw['uid'] = uid return ldap.search(**kw) def output_for_cli(self, users): if not users: @@ -244,7 +240,7 @@ class user_find(crud.Find): counter = users[0] users = users[1:] if counter == 0: - print "No entries found for", args[0] + print "No entries found" return elif counter == -1: print "These results are truncated." @@ -272,7 +268,7 @@ class user_show(crud.Get): """ ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("uid", uid, "posixAccount") - # FIXME: should kw contain the list of attributes? + # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) api.register(user_show) @@ -282,10 +278,10 @@ class user_lock(frontend.Command): takes_args = ( Param('uid', primary_key=True), ) - def execute(self, *args, **kw): - uid = args[0] - user = servercore.get_user_by_uid(uid, ['dn', 'uid']) - return servercore.mark_entry_inactive(user['dn']) + def execute(self, uid, **kw): + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, "posixAccount") + return ldap.mark_entry_inactive(dn) def output_for_cli(self, ret): if ret: print "User locked" @@ -296,10 +292,10 @@ class user_unlock(frontend.Command): takes_args = ( Param('uid', primary_key=True), ) - def execute(self, *args, **kw): - uid = args[0] - user = servercore.get_user_by_uid(uid, ['dn', 'uid']) - return servercore.mark_entry_active(user['dn']) + def execute(self, uid, **kw): + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("uid", uid, "posixAccount") + return ldap.mark_entry_active(dn) def output_for_cli(self, ret): if ret: print "User unlocked" -- cgit From 5748fce84ca0c0256183e1da308cb9f7ae4e73de Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 16 Oct 2008 10:59:03 -0400 Subject: Remove references to ipa_server.* and port group plugin to ldap backend --- ipalib/plugins/f_group.py | 144 +++++++++++++++++++++++++++------------------- 1 file changed, 85 insertions(+), 59 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index a07d314b..c2280a4e 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -25,10 +25,7 @@ from ipalib import frontend from ipalib import crud from ipalib.frontend import Param from ipalib import api -from ipa_server import servercore -from ipa_server import ipaldap from ipa_server import ipautil -import ldap class group(frontend.Object): @@ -71,7 +68,7 @@ class group_add(crud.Add): kw['dn'] = ldap.make_group_dn(cn) # Get our configuration - config = servercore.get_ipa_config() + config = ldap.get_ipa_config() # some required objectclasses kw['objectClass'] = config.get('ipagroupobjectclasses') @@ -90,87 +87,116 @@ api.register(group_add) class group_del(crud.Del): 'Delete an existing group.' - def execute(self, *args, **kw): - """args[0] = dn of the group to remove - - Delete a group - - The memberOf plugin handles removing the group from any other - groups. + def execute(self, cn, **kw): """ - group_dn = args[0] + Delete a group - group = servercore.get_entry_by_dn(group_dn, ['dn', 'cn']) - if group is None: - raise errors.NotFound -# logging.info("IPA: delete_group '%s'" % group_dn) + The memberOf plugin handles removing the group from any other + groups. + :param cn: The name of the group being removed + :param kw: Unused + """ # We have 2 special groups, don't allow them to be removed - # FIXME -# if "admins" in group.get('cn') or "editors" in group.get('cn'): +# if "admins" == cn.lower() or "editors" == cn.lower(): # raise ipaerror.gen_exception(ipaerror.CONFIG_REQUIRED_GROUPS) + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, "posixGroup") +# logging.info("IPA: delete_group '%s'" % dn) + # Don't allow the default user group to be removed - config=servercore.get_ipa_config() - default_group = servercore.get_entry_by_cn(config.get('ipadefaultprimarygroup'), None) - if group_dn == default_group.get('dn'): + config=ldap.get_ipa_config() + default_group = ldap.find_entry_dn("cn", config.get('ipadefaultprimarygroup'), "posixGroup") + if dn == default_group: raise errors.DefaultGroup - return servercore.delete_entry(group_dn) - def forward(self, *args, **kw): - group = self.api.Command['group_show'](ipautil.utf8_encode_value(args[0])) - if not group: - print "nothing found" - return False - a = group.get('dn') - result = super(crud.Del, self).forward(a) + return ldap.delete(dn) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Group deleted" + api.register(group_del) class group_mod(crud.Mod): 'Edit an existing group.' - def execute(self, *args, **kw): - group_cn=args[0] - result = servercore.get_entry_by_cn(group_cn, ["*"]) + def execute(self, cn, **kw): + """ + Execute the user-mod operation. - group = kw - dn = result.get('dn') - del result['dn'] - entry = ipaldap.Entry((dn, servercore.convert_scalar_values(result))) + The dn should not be passed as a keyword argument as it is constructed + by this method. - for g in group: - entry.setValues(g, group[g]) + Returns the entry - result = servercore.update_entry(entry.toDict()) + :param cn: The name of the group to update. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, "posixGroup") + return ldap.update(dn, **kw) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Group updated" - return result - def forward(self, *args, **kw): - result = super(crud.Mod, self).forward(*args, **kw) - if result: - print "Group %s modified" % args[0] api.register(group_mod) class group_find(crud.Find): 'Search the groups.' - def execute(self, *args, **kw): - cn=args[0] - result = servercore.get_sub_entry(servercore.basedn, "cn=%s" % cn, ["*"]) - return result - def forward(self, *args, **kw): - result = super(crud.Find, self).forward(*args, **kw) - for a in result: - print a, ": ", result[a] + def execute(self, cn, **kw): + ldap = self.api.Backend.ldap + kw['cn'] = cn + return ldap.search(**kw) + + def output_for_cli(self, groups): + if not groups: + return + + counter = groups[0] + groups = groups[1:] + if counter == 0: + print "No entries found" + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for g in groups: + for a in g.keys(): + print "%s: %s" % (a, g[a]) + api.register(group_find) class group_show(crud.Get): 'Examine an existing group.' - def execute(self, *args, **kw): - cn=args[0] - result = servercore.get_sub_entry(servercore.basedn, "cn=%s" % cn, ["*"]) - return result - def forward(self, *args, **kw): - result = super(crud.Get, self).forward(*args, **kw) - return result + def execute(self, cn, **kw): + """ + Execute the group-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param cn: The group name to retrieve. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, "posixGroup") + # FIXME: should kw contain the list of attributes to display? + return ldap.retrieve(dn) + api.register(group_show) -- cgit From f777f72de6a7c1d3ef29088fbf89722c1148f246 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 16 Oct 2008 15:00:30 -0400 Subject: Use the search fields from the configuration when searching Generalize the attribute -> objectclass search helper --- ipalib/plugins/f_group.py | 15 +++++++++++++-- ipalib/plugins/f_user.py | 25 ++++++++++++++++++------- 2 files changed, 31 insertions(+), 9 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index c2280a4e..132e45ef 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -155,9 +155,20 @@ api.register(group_mod) class group_find(crud.Find): 'Search the groups.' - def execute(self, cn, **kw): + def execute(self, term, **kw): ldap = self.api.Backend.ldap - kw['cn'] = cn + + # Pull the list of searchable attributes out of the configuration. + config = ldap.get_ipa_config() + search_fields_conf_str = config.get('ipagroupsearchfields') + search_fields = search_fields_conf_str.split(",") + + for s in search_fields: + kw[s] = term + + object_type = ldap.get_object_type("cn") + if object_type and not kw.get('objectclass'): + kw['objectclass'] = ldap.get_object_type("cn") return ldap.search(**kw) def output_for_cli(self, groups): diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 9fec1bd4..da0262b6 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -186,7 +186,7 @@ class user_del(crud.Del): # logging.info("IPA: delete_user '%s'" % uid) ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid, "posixAccount") + dn = ldap.find_entry_dn("uid", uid) return ldap.delete(dn) def output_for_cli(self, ret): """ @@ -215,7 +215,7 @@ class user_mod(crud.Mod): assert 'uid' not in kw assert 'dn' not in kw ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid, "posixAccount") + dn = ldap.find_entry_dn("uid", uid) return ldap.update(dn, **kw) def output_for_cli(self, ret): @@ -230,9 +230,20 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' - def execute(self, uid, **kw): + def execute(self, term, **kw): ldap = self.api.Backend.ldap - kw['uid'] = uid + + # Pull the list of searchable attributes out of the configuration. + config = ldap.get_ipa_config() + search_fields_conf_str = config.get('ipausersearchfields') + search_fields = search_fields_conf_str.split(",") + + for s in search_fields: + kw[s] = term + + object_type = ldap.get_object_type("uid") + if object_type and not kw.get('objectclass'): + kw['objectclass'] = ldap.get_object_type("uid") return ldap.search(**kw) def output_for_cli(self, users): if not users: @@ -267,7 +278,7 @@ class user_show(crud.Get): :param kw: Not used. """ ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid, "posixAccount") + dn = ldap.find_entry_dn("uid", uid) # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) @@ -280,7 +291,7 @@ class user_lock(frontend.Command): ) def execute(self, uid, **kw): ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid, "posixAccount") + dn = ldap.find_entry_dn("uid", uid) return ldap.mark_entry_inactive(dn) def output_for_cli(self, ret): if ret: @@ -294,7 +305,7 @@ class user_unlock(frontend.Command): ) def execute(self, uid, **kw): ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("uid", uid, "posixAccount") + dn = ldap.find_entry_dn("uid", uid) return ldap.mark_entry_active(dn) def output_for_cli(self, ret): if ret: -- cgit From b045f220692e016a105f03af025d49f9a9cddc74 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 16 Oct 2008 23:33:44 -0400 Subject: Add mod_python-based XML-RPC server. Use -e kerberos on the command-line to use the mod_python server, otherwise it defaults to use the simple-server URL. --- ipalib/plugins/b_xmlrpc.py | 47 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index db2af1ab..9fe5b133 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -1,5 +1,6 @@ # Authors: # Jason Gerard DeRose +# Rob Crittenden # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty information @@ -26,6 +27,8 @@ This provides a lightwieght XML-RPC client using Python standard library import xmlrpclib import socket +import httplib +import kerberos from ipalib.backend import Backend from ipalib.util import xmlrpc_marshal from ipalib import api @@ -38,7 +41,12 @@ class xmlrpc(Backend): def get_client(self, verbose=False): # FIXME: The server uri should come from self.api.env.server_uri - return xmlrpclib.ServerProxy('http://localhost:8888', verbose=verbose) + if api.env.get('kerberos'): + server = api.env.server.next() + if verbose: print "Connecting to %s" % server + return xmlrpclib.ServerProxy('https://%s/ipa/xml' % server, transport=KerbTransport(), verbose=verbose) + else: + return xmlrpclib.ServerProxy('http://localhost:8888', verbose=verbose) def forward_call(self, name, *args, **kw): """ @@ -54,10 +62,41 @@ class xmlrpc(Backend): except xmlrpclib.Fault, e: err = errors.convertFault(e) code = getattr(err,'faultCode',None) - if code: - print "%s: %s" % (code, getattr(err,'__doc__','')) - else: + faultString = getattr(err,'faultString',None) + if not code: raise err + if code < errors.IPA_ERROR_BASE: + print "%s: %s" % (code, faultString) + else: + print "%s: %s" % (code, getattr(err,'__doc__','')) return {} api.register(xmlrpc) + +class KerbTransport(xmlrpclib.SafeTransport): + """Handles Kerberos Negotiation authentication to an XML-RPC server.""" + + def get_host_info(self, host): + + host, extra_headers, x509 = xmlrpclib.Transport.get_host_info(self, host) + + # Set the remote host principal + h = host + hostinfo = h.split(':') + service = "HTTP@" + hostinfo[0] + + try: + rc, vc = kerberos.authGSSClientInit(service); + except kerberos.GSSError, e: + raise kerberos.GSSError(e) + + try: + kerberos.authGSSClientStep(vc, ""); + except kerberos.GSSError, e: + raise kerberos.GSSError(e) + + extra_headers = [ + ("Authorization", "negotiate %s" % kerberos.authGSSClientResponse(vc) ) + ] + + return host, extra_headers, x509 -- cgit From ae8370be44d95b9f6793ded46ef81126aebef3e0 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 17 Oct 2008 19:20:23 -0400 Subject: Port f_service to LDAP backend Add new keyword, 'filter', that can be passed to the search function. This is globbed onto the filter that is auto-created. --- ipalib/plugins/f_group.py | 2 +- ipalib/plugins/f_service.py | 137 +++++++++++++++++++++++++++++--------------- ipalib/plugins/f_user.py | 2 +- 3 files changed, 94 insertions(+), 47 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index 132e45ef..e83c870e 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -168,7 +168,7 @@ class group_find(crud.Find): object_type = ldap.get_object_type("cn") if object_type and not kw.get('objectclass'): - kw['objectclass'] = ldap.get_object_type("cn") + kw['objectclass'] = object_type return ldap.search(**kw) def output_for_cli(self, groups): diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index baed5233..38c80ad2 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -1,5 +1,6 @@ # Authors: # Jason Gerard DeRose +# Rob Crittenden # # Copyright (C) 2008 Red Hat # see file 'COPYING' for use and warranty information @@ -27,9 +28,6 @@ from ipalib.frontend import Param from ipalib import api from ipalib import errors from ipalib import ipa_types -from ipa_server import servercore -from ipa_server import ipaldap -import ldap class service(frontend.Object): """ @@ -46,13 +44,26 @@ class service_add(crud.Add): takes_options = ( Param('force?', type=ipa_types.Bool(), default=False, doc='Force a service principal name'), ) - def execute(self, *args, **kw): - """args[0] = service principal to add - kw{force} determines whether we continue on errors + def execute(self, principal, **kw): """ - force = kw.get('force', False) + Execute the service-add operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. - principal = args[0] + Returns the entry as it will be created in LDAP. + + :param principal: The service to be added in the form: service/hostname + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'krbprincipalname' not in kw + ldap = self.api.Backend.ldap + + force = kw.get('force', False) + try: + del kw['force'] + except: + pass # Break down the principal into its component parts, which may or # may not include the realm. @@ -64,7 +75,7 @@ class service_add(crud.Add): sr = sp[1].split('@') if len(sr) == 1: hostname = sr[0].lower() - realm = servercore.realm + realm = self.api.env.realm elif len(sr) == 2: hostname = sr[0].lower() realm = sr[1] @@ -83,68 +94,104 @@ class service_add(crud.Add): logging.debug("IPA: found %d records for '%s'" % (len(rs), hostname)) """ - service_container = servercore.DefaultServiceContainer - # At some point we'll support multiple realms - if (realm != servercore.realm): + if (realm != self.api.env.realm): raise errors.RealmMismatch # Put the principal back together again princ_name = service + "/" + hostname + "@" + realm - dn = "krbprincipalname=%s,%s,%s" % (ldap.dn.escape_dn_chars(princ_name), - service_container,servercore.basedn) - entry = ipaldap.Entry(dn) + dn = ldap.make_service_dn(princ_name) - entry.setValues('objectClass', 'krbPrincipal', 'krbPrincipalAux', 'krbTicketPolicyAux') - entry.setValues('krbprincipalname', princ_name) + kw['dn'] = dn + kw['objectClass'] = ['krbPrincipal', 'krbPrincipalAux', 'krbTicketPolicyAux'] + + return ldap.create(**kw) + + def output_to_cli(self, ret): + if ret: + print "Service added" - result = servercore.add_entry(entry) - return result - def forward(self, *args, **kw): - result = super(crud.Add, self).forward(*args, **kw) - if result: - print "Service %s added" % args[0] api.register(service_add) class service_del(crud.Del): 'Delete an existing service.' - def execute(self, *args, **kw): - """args[0] = princial to remove + def execute(self, principal, **kw): + """ + Delete a service principal. - Delete a service principal. + principal is the krbprincipalname of the entry to delete. - principal is the full DN of the entry to delete. + This should be called with much care. - This should be called with much care. + :param principal: The service to be added in the form: service/hostname + :param kw: not used """ - principal = args[0] - return False - def forward(self, *args, **kw): - result = super(crud.Del, self).forward(*args, **kw) - if result: - print "Service %s removed" % args[0] -api.register(service_del) + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("krbprincipalname", principal) + return ldap.delete(dn) + def output_to_cli(self, ret): + if ret: + print "Service removed" -class service_mod(crud.Mod): - 'Edit an existing service.' -api.register(service_mod) +api.register(service_del) +# There is no service-mod. The principal itself contains nothing that +# is user-changeable class service_find(crud.Find): 'Search the existing services.' + def execute(self, principal, **kw): + ldap = self.api.Backend.ldap + + kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=person))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" + kw['krbprincipalname'] = principal + + object_type = ldap.get_object_type("krbprincipalname") + if object_type and not kw.get('objectclass'): + kw['objectclass'] = object_type + + return ldap.search(**kw) + + def output_for_cli(self, services): + if not services: + return + + counter = services[0] + services = services[1:] + if counter == 0: + print "No entries found" + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for s in services: + for a in s.keys(): + print "%s: %s" % (a, s[a]) + api.register(service_find) class service_show(crud.Get): 'Examine an existing service.' - def execute(self, *args, **kw): - filter = "(&(objectclass=krbPrincipalAux)(!(objectClass=person))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))(&(|(krbprincipalname=%s))))" % args[0] - result = servercore.get_sub_entry(servercore.basedn, filter, ["*"]) - return result - def forward(self, *args, **kw): - result = super(crud.Get, self).forward(*args, **kw) - return result + def execute(self, principal, **kw): + """ + Execute the service-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param principal: The service principal to retrieve + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("krbprincipalname", principal) + # FIXME: should kw contain the list of attributes to display? + return ldap.retrieve(dn) + api.register(service_show) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index da0262b6..8b4def80 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -243,7 +243,7 @@ class user_find(crud.Find): object_type = ldap.get_object_type("uid") if object_type and not kw.get('objectclass'): - kw['objectclass'] = ldap.get_object_type("uid") + kw['objectclass'] = object_type return ldap.search(**kw) def output_for_cli(self, users): if not users: -- cgit From d615e4dafb9c4f3d737143f826ed20be918317fe Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 20 Oct 2008 16:12:19 -0400 Subject: Port pwpolicy plugin to use b_ldap Add basic output_for_cli() function to user-show --- ipalib/plugins/f_pwpolicy.py | 117 +++++++++++++++++++++++++++---------------- ipalib/plugins/f_user.py | 4 ++ 2 files changed, 79 insertions(+), 42 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_pwpolicy.py b/ipalib/plugins/f_pwpolicy.py index 36e232dc..ce52e467 100644 --- a/ipalib/plugins/f_pwpolicy.py +++ b/ipalib/plugins/f_pwpolicy.py @@ -27,65 +27,92 @@ from ipalib.frontend import Param from ipalib import api from ipalib import errors from ipalib import ipa_types -from ipa_server import servercore -from ipa_server import ipaldap -import ldap class pwpolicy_mod(frontend.Command): 'Edit existing password policy.' - # FIXME, switch to more human-readable names at some point takes_options = ( - Param('krbmaxpwdlife?', type=ipa_types.Int(), doc='Max. Password Lifetime (days)'), - Param('krbminpwdlife?', type=ipa_types.Int(), doc='Min. Password Lifetime (hours)'), - Param('krbpwdhistorylength?', type=ipa_types.Int(), doc='Password History Size'), - Param('krbpwdmindiffchars?', type=ipa_types.Int(), doc='Min. Number of Character Classes'), - Param('krbpwdminlength?', type=ipa_types.Int(), doc='Min. Length of Password'), + Param('krbmaxpwdlife?', + cli_name='maxlife', + type=ipa_types.Int(), + doc='Max. Password Lifetime (days)' + ), + Param('krbminpwdlife?', + cli_name='minlife', + type=ipa_types.Int(), + doc='Min. Password Lifetime (hours)' + ), + Param('krbpwdhistorylength?', + cli_name='history', + type=ipa_types.Int(), + doc='Password History Size' + ), + Param('krbpwdmindiffchars?', + cli_name='minclasses', + type=ipa_types.Int(), + doc='Min. Number of Character Classes' + ), + Param('krbpwdminlength?', + cli_name='minlength', + type=ipa_types.Int(), + doc='Min. Length of Password' + ), ) def execute(self, *args, **kw): - # Get the existing policy entry - oldpolicy = servercore.get_entry_by_cn("accounts", None) + """ + Execute the pwpolicy-mod operation. - # Convert the existing policy into an entry object - dn = oldpolicy.get('dn') - del oldpolicy['dn'] - entry = ipaldap.Entry((dn, servercore.convert_scalar_values(oldpolicy))) + The dn should not be passed as a keyword argument as it is constructed + by this method. - # FIXME: if the user passed no options should we return something - # more than No modifications to be performed? + Returns the entry - policy = kw + :param args: This function takes no positional arguments + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", "accounts", "krbPwdPolicy") # The LDAP routines want strings, not ints, so convert a few # things. Otherwise it sees a string -> int conversion as a change. - for k in policy.iterkeys(): + for k in kw.iterkeys(): if k.startswith("krb", 0, 3): - policy[k] = str(policy[k]) - - # Convert hours and days to seconds - if policy.get('krbmaxpwdlife'): - policy['krbmaxpwdlife'] = str(int(policy.get('krbmaxpwdlife')) * 86400) - if policy.get('krbminpwdlife'): - policy['krbminpwdlife'] = str(int(policy.get('krbminpwdlife')) * 3600) - # Update the values passed-in - for p in policy: - # Values need to be strings, not integers - entry.setValues(p, str(policy[p])) - - result = servercore.update_entry(entry.toDict()) - - return result - def forward(self, *args, **kw): - result = super(pwpolicy_mod, self).forward(*args, **kw) - if result: + kw[k] = str(kw[k]) + + # Convert hours and days to seconds + if kw.get('krbmaxpwdlife'): + kw['krbmaxpwdlife'] = str(int(kw.get('krbmaxpwdlife')) * 86400) + if kw.get('krbminpwdlife'): + kw['krbminpwdlife'] = str(int(kw.get('krbminpwdlife')) * 3600) + + return ldap.update(dn, **kw) + + def output_for_cli(self, ret): + if ret: print "Policy modified" + api.register(pwpolicy_mod) class pwpolicy_show(frontend.Command): 'Retrieve current password policy' def execute(self, *args, **kw): - policy = servercore.get_entry_by_cn("accounts", None) + """ + Execute the pwpolicy-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param args: Not used. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", "accounts", "krbPwdPolicy") + + policy = ldap.retrieve(dn) # convert some values for display purposes policy['krbmaxpwdlife'] = str(int(policy.get('krbmaxpwdlife')) / 86400) @@ -93,8 +120,14 @@ class pwpolicy_show(frontend.Command): return policy - def forward(self, *args, **kw): - result = super(pwpolicy_show, self).forward(*args, **kw) - if not result: return - print result + def output_for_cli(self, policy): + if not policy: return + + print "Password Policy" + print "Min. Password Lifetime (hours): %s" % policy.get('krbminpwdlife') + print "Max. Password Lifetime (days): %s" % policy.get('krbmaxpwdlife') + print "Min. Number of Character Classes: %s" % policy.get('krbpwdmindiffchars') + print "Min. Length of Password: %s" % policy.get('krbpwdminlength') + print "Password History Size: %s" % policy.get('krbpwdhistorylength') + api.register(pwpolicy_show) diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 8b4def80..6aebddfa 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -281,6 +281,10 @@ class user_show(crud.Get): dn = ldap.find_entry_dn("uid", uid) # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) + def output_for_cli(self, user): + if user: + for a in user.keys(): + print "%s: %s" % (a, user[a]) api.register(user_show) -- cgit From 8c54f730c0a156543f23ca90b6220ddd89d76dcc Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 20 Oct 2008 22:41:53 -0400 Subject: Framework for doing password changes Need mechanism to prompt for new password twice and verify they are the same --- ipalib/plugins/f_passwd.py | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 ipalib/plugins/f_passwd.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py new file mode 100644 index 00000000..b1f90732 --- /dev/null +++ b/ipalib/plugins/f_passwd.py @@ -0,0 +1,82 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for password changes. +""" + +from ipalib import frontend +from ipalib.frontend import Param +from ipalib import api +from ipalib import errors +from ipalib import ipa_types +import krbV + +def get_current_principal(): + try: + return krbV.default_context().default_ccache().principal().name + except krbV.Krb5Error: + #TODO: do a kinit + print "Unable to get kerberos principal" + return None + +class passwd(frontend.Command): + 'Edit existing password policy.' + takes_args = ( + Param('principal', + cli_name='user', + primary_key=True, + default_from=get_current_principal, + ), + ) + def execute(self, principal, **kw): + """ + Execute the passwd operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param param uid: The login name of the user being updated. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + + if principal.find('@') < 0: + u = principal.split('@') + if len(u) > 2 or len(u) == 0: + print "Invalid user name (%s)" % principal + if len(u) == 1: + principal = principal+"@"+self.api.env.realm + else: + principal = principal + + dn = ldap.find_entry_dn("krbprincipalname", principal, "person") + + # FIXME: we need a way to prompt for passwords using getpass + kw['newpass'] = "password" + + return ldap.modify_password(dn, **kw) + + def output_for_cli(self, ret): + if ret: + print "Password change successful" + +api.register(passwd) -- cgit From 475265ed378cd0879d22e2b9bc59f7eab742fee9 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 21 Oct 2008 09:31:44 -0400 Subject: Implement --all option to display all attributes. Still need to strip the dn when not doing all. --- ipalib/plugins/f_user.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 6aebddfa..972ee075 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -265,6 +265,9 @@ api.register(user_find) class user_show(crud.Get): 'Examine an existing user.' + takes_options = ( + Param('all?', type=ipa_types.Bool(), doc='Display all user attributes'), + ) def execute(self, uid, **kw): """ Execute the user-show operation. @@ -275,12 +278,15 @@ class user_show(crud.Get): Returns the entry :param uid: The login name of the user to retrieve. - :param kw: Not used. + :param kw: "all" set to True = return all attributes """ ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("uid", uid) # FIXME: should kw contain the list of attributes to display? - return ldap.retrieve(dn) + if kw.get('all', False): + return ldap.retrieve(dn) + else: + return ldap.retrieve(dn, ['uid','givenname','sn','homeDirectory','loginshell']) def output_for_cli(self, user): if user: for a in user.keys(): -- cgit From 8d07faed4df28b8397971d06a2b101078c88ef86 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 21 Oct 2008 16:32:30 -0400 Subject: Update the command-line options to more closely match v1 --- ipalib/plugins/f_user.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 972ee075..70952b29 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -55,11 +55,11 @@ class user(frontend.Object): takes_params = ( Param('givenname', cli_name='first', - doc='User first name', + doc='User\'s first name', ), Param('sn', cli_name='last', - doc='User last name', + doc='User\'s last name', ), Param('uid', cli_name='user', @@ -68,22 +68,40 @@ class user(frontend.Object): normalize=lambda value: value.lower(), ), Param('gecos?', - doc='GECOS field', + doc='Set the GECOS field', default_from=lambda uid: uid, ), Param('homedirectory?', cli_name='home', - doc='Path of user home directory', + doc='Set the User\'s home directory', default_from=lambda uid: '/home/%s' % uid, ), Param('loginshell?', cli_name='shell', default=u'/bin/sh', - doc='Login shell', + doc='Set User\'s Login shell', ), Param('krbprincipalname?', cli_name='principal', - default_from=lambda uid: '%s@EXAMPLE.COM' % uid, + doc='Set User\'s Kerberos Principal name', + default_from=lambda uid: '%s@%s' % (uid, api.env.realm), ), + Param('mailaddress?', + cli_name='mail', + doc='Set User\'s e-mail address', + ), + Param('userpassword?', + cli_name='password', + doc='Set User\'s password', + ), + Param('groups?', + doc='Add account to one or more groups (comma-separated)', + ), + Param('uidnumber?', + cli_name='uid', + type=ipa_types.Int(), + doc='The uid to use for this user. If not included one is automatically set.', + ), + ) api.register(user) -- cgit From 3cbb5c6eeb131e931e4489eafd434079442ca3a7 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 21 Oct 2008 16:32:45 -0400 Subject: Don't import servercore --- ipalib/plugins/f_delegation.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_delegation.py b/ipalib/plugins/f_delegation.py index 1fb2b4f9..fbf8cfbf 100644 --- a/ipalib/plugins/f_delegation.py +++ b/ipalib/plugins/f_delegation.py @@ -26,9 +26,6 @@ from ipalib import crud from ipalib.frontend import Param from ipalib import api from ipalib import errors -from ipa_server import servercore -from ipa_server import ipaldap -import ldap class delegation(frontend.Object): """ -- cgit From 245969858d8484428db1edbff8d6bd36587fb144 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 21 Oct 2008 16:33:34 -0400 Subject: Implement group member add/remove Add gidNumber to the group command-line --- ipalib/plugins/f_group.py | 151 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index e83c870e..b5f80f93 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -25,7 +25,8 @@ from ipalib import frontend from ipalib import crud from ipalib.frontend import Param from ipalib import api -from ipa_server import ipautil +from ipalib import errors +from ipalib import ipa_types class group(frontend.Object): @@ -33,7 +34,14 @@ class group(frontend.Object): Group object. """ takes_params = ( - 'description', + Param('description', + doc='A description of this group', + ), + Param('gidnumber?', + cli_name='gid', + type=ipa_types.Int(), + doc='The gid to use for this group. If not included one is automatically set.', + ), Param('cn', cli_name='name', primary_key=True, @@ -210,4 +218,143 @@ class group_show(crud.Get): # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) + def output_for_cli(self, group): + if not group: + return + + for a in group.keys(): + print "%s: %s" % (a, group[a]) + api.register(group_show) + + +class group_add_member(frontend.Command): + 'Add a member to a group.' + takes_args = ( + Param('group', primary_key=True), + ) + takes_options = ( + Param('users?', doc='comma-separated list of users to add'), + Param('groups?', doc='comma-separated list of groups to add'), + ) + def execute(self, cn, **kw): + """ + Execute the group-add-member operation. + + Returns the updated group entry + + :param cn: The group name to add new members to. + :param kw: groups is a comma-separated list of groups to add + :parem kw: users is a comma-separated list of users to add + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn) + add_failed = [] + to_add = [] + completed = 0 + + members = kw.get('groups', '').split(',') + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn("cn", m) + to_add.append(member_dn) + except errors.NotFound: + add_failed.append(m) + continue + + members = kw.get('users', '').split(',') + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn("uid", m) + to_add.append(member_dn) + except errors.NotFound: + add_failed.append(m) + continue + + for member_dn in to_add: + try: + ldap.add_member_to_group(member_dn, dn) + completed+=1 + except: + add_failed.append(member_dn) + + return add_failed + + def output_for_cli(self, add_failed): + """ + Output result of this command to command line interface. + """ + if add_failed: + print "These entries failed to add to the group:" + for a in add_failed: + print "\t'%s'" % a + + +api.register(group_add_member) + + +class group_remove_member(frontend.Command): + 'Remove a member from a group.' + takes_args = ( + Param('group', primary_key=True), + ) + takes_options = ( + Param('users?', doc='comma-separated list of users to remove'), + Param('groups?', doc='comma-separated list of groups to remove'), + ) + def execute(self, cn, **kw): + """ + Execute the group-remove-member operation. + + Returns the members that could not be added + + :param cn: The group name to add new members to. + :param kw: groups is a comma-separated list of groups to remove + :parem kw: users is a comma-separated list of users to remove + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn) + to_remove = [] + remove_failed = [] + completed = 0 + + members = kw.get('groups', '').split(',') + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn("cn", m) + to_remove.append(member_dn) + except errors.NotFound: + remove_failed.append(m) + continue + + members = kw.get('users', '').split(',') + for m in members: + try: + member_dn = ldap.find_entry_dn("uid", m,) + to_remove.append(member_dn) + except errors.NotFound: + remove_failed.append(m) + continue + + for member_dn in to_remove: + try: + ldap.remove_member_from_group(member_dn, dn) + completed+=1 + except: + remove_failed.append(member_dn) + + return remove_failed + + def output_for_cli(self, remove_failed): + """ + Output result of this command to command line interface. + """ + if remove_failed: + print "These entries failed to be removed from the group:" + for a in remove_failed: + print "\t'%s'" % a + +api.register(group_remove_member) -- cgit From 1daf319a19f902d7c7bef37af065cac81be9189e Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 22 Oct 2008 17:54:04 -0400 Subject: Implement the host commands In order for this to work against a v1 database the update host.update needs to be applied --- ipalib/plugins/b_xmlrpc.py | 2 +- ipalib/plugins/f_host.py | 271 +++++++++++++++++++++++++++++++++++++++++++++ ipalib/plugins/f_passwd.py | 12 +- 3 files changed, 274 insertions(+), 11 deletions(-) create mode 100644 ipalib/plugins/f_host.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 9fe5b133..572a7511 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -69,7 +69,7 @@ class xmlrpc(Backend): print "%s: %s" % (code, faultString) else: print "%s: %s" % (code, getattr(err,'__doc__','')) - return {} + return api.register(xmlrpc) diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py new file mode 100644 index 00000000..da281548 --- /dev/null +++ b/ipalib/plugins/f_host.py @@ -0,0 +1,271 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for host/machine Identity. +""" + +from ipalib import frontend +from ipalib import crud +from ipalib import util +from ipalib.frontend import Param +from ipalib import api +from ipalib import errors +from ipalib import ipa_types + + +def get_host(hostname): + """ + Try to get the hostname as fully-qualified first, then fall back to + just a host name search. + """ + ldap = api.Backend.ldap + + # Strip off trailing dot + if hostname.endswith('.'): + hostname = hostname[:-1] + try: + dn = ldap.find_entry_dn("cn", hostname, "ipaHost") + except errors.NotFound: + dn = ldap.find_entry_dn("serverhostname", hostname, "ipaHost") + return dn + +def validate_host(cn): + """ + Require at least one dot in the hostname (to support localhost.localdomain) + """ + dots = len(cn.split('.')) + if dots < 2: + return 'Fully-qualified hostname required' + return None + + +class host(frontend.Object): + """ + Host object. + """ + takes_params = ( + Param('cn', + cli_name='hostname', + primary_key=True, + normalize=lambda value: value.lower(), + rules=(validate_host,) + ), + Param('description?', + doc='Description of the host', + ), + Param('localityname?', + cli_name='locality', + doc='Locality of this host (Baltimore, MD)', + ), + Param('nshostlocation?', + cli_name='location', + doc='Location of this host (e.g. Lab 2)', + ), + Param('nshardwareplatform?', + cli_name='platform', + doc='Hardware platform of this host (e.g. Lenovo T61)', + ), + Param('nsosversion?', + cli_name='os', + doc='Operating System and version on this host (e.g. Fedora 9)', + ), + Param('userpassword?', + cli_name='password', + doc='Set a password to be used in bulk enrollment', + ), + ) +api.register(host) + + +class host_add(crud.Add): + 'Add a new host.' + def execute(self, hostname, **kw): + """ + Execute the host-add operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry as it will be created in LDAP. + + :param hostname: The name of the host being added. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + + kw['cn'] = hostname + kw['serverhostname'] = hostname.split('.',1)[0] + kw['dn'] = ldap.make_host_dn(hostname) + kw['krbPrincipalName'] = "host/%s@%s" % (hostname, self.api.env.realm) + + # FIXME: do a DNS lookup to ensure host exists + + current = util.get_current_principal() + if not current: + raise errors.NotFound('Unable to determine current user') + kw['enrolledBy'] = ldap.find_entry_dn("krbPrincipalName", current, "person") + + # Get our configuration + config = ldap.get_ipa_config() + + # some required objectclasses + # FIXME: add this attribute to cn=ipaconfig + #kw['objectClass'] = config.get('ipahostobjectclasses') + kw['objectClass'] = ['nsHost', 'krbPrincipalAux', 'ipaHost'] + + return ldap.create(**kw) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Host added" + +api.register(host_add) + + +class host_del(crud.Del): + 'Delete an existing host.' + def execute(self, hostname, **kw): + """Delete a host. + + hostname is the name of the host to delete + + :param hostname: The name of the host being removed. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = get_host(hostname) + return ldap.delete(dn) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Host deleted" + +api.register(host_del) + + +class host_mod(crud.Mod): + 'Edit an existing host.' + def execute(self, hostname, **kw): + """ + Execute the host-mod operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param hostname: The name of the host to retrieve. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = get_host(hostname) + return ldap.update(dn, **kw) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Host updated" + +api.register(host_mod) + + +class host_find(crud.Find): + 'Search the hosts.' + def get_args(self): + """ + Override Find.get_args() so we can exclude the validation rules + """ + yield self.obj.primary_key.__clone__(rules=tuple()) + def execute(self, term, **kw): + ldap = self.api.Backend.ldap + + # Pull the list of searchable attributes out of the configuration. + #config = ldap.get_ipa_config() + # FIXME: add this attribute to cn=ipaconfig + #search_fields_conf_str = config.get('ipahostsearchfields') + #search_fields = search_fields_conf_str.split(",") + search_fields = ['cn','serverhostname','description','localityname','nshostlocation','nshardwareplatform','nsosversion'] + + for s in search_fields: + kw[s] = term + + # Can't use ldap.get_object_type() since cn is also used for group dns + kw['objectclass'] = "ipaHost" + return ldap.search(**kw) + def output_for_cli(self, hosts): + if not hosts: + return + counter = hosts[0] + hosts = hosts[1:] + if counter == 0: + print "No entries found" + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for h in hosts: + for a in h.keys(): + print "%s: %s" % (a, h[a]) +api.register(host_find) + + +class host_show(crud.Get): + 'Examine an existing host.' + takes_options = ( + Param('all?', type=ipa_types.Bool(), doc='Display all host attributes'), + ) + def execute(self, hostname, **kw): + """ + Execute the host-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param hostname: The login name of the host to retrieve. + :param kw: "all" set to True = return all attributes + """ + ldap = self.api.Backend.ldap + dn = get_host(hostname) + # FIXME: should kw contain the list of attributes to display? + if kw.get('all', False): + return ldap.retrieve(dn) + else: + value = ldap.retrieve(dn, ['cn','description','localityname','nshostlocation','nshardwareplatform','nsosversion']) + del value['dn'] + return value + def output_for_cli(self, host): + if host: + for a in host.keys(): + print "%s: %s" % (a, host[a]) + +api.register(host_show) diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py index b1f90732..f70eacac 100644 --- a/ipalib/plugins/f_passwd.py +++ b/ipalib/plugins/f_passwd.py @@ -26,15 +26,7 @@ from ipalib.frontend import Param from ipalib import api from ipalib import errors from ipalib import ipa_types -import krbV - -def get_current_principal(): - try: - return krbV.default_context().default_ccache().principal().name - except krbV.Krb5Error: - #TODO: do a kinit - print "Unable to get kerberos principal" - return None +from ipalib import util class passwd(frontend.Command): 'Edit existing password policy.' @@ -42,7 +34,7 @@ class passwd(frontend.Command): Param('principal', cli_name='user', primary_key=True, - default_from=get_current_principal, + default_from=util.get_current_principal, ), ) def execute(self, principal, **kw): -- cgit From d2b46f176e5dbc40b67ebd90e6953498c5d6249a Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 23 Oct 2008 14:36:24 -0400 Subject: Use common display function for user-show and user-find. Add --all option to user-find Fix command-line help to make sense on searches as well --- ipalib/plugins/f_user.py | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 70952b29..d8bb49e2 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -47,6 +47,24 @@ class envtest(frontend.Command): return {} api.register(envtest) +def display_user(user): + # FIXME: for now delete dn here. In the future pass in the kw to + # output_for_cli() + attr = sorted(user.keys()) + # Always have sn following givenname + try: + l = attr.index('givenname') + attr.remove('sn') + attr.insert(l+1, 'sn') + except ValueError: + pass + + for a in attr: + if a != 'dn': + print "%s: %s" % (a, user[a]) + +default_attributes = ['uid','givenname','sn','homeDirectory','loginshell'] + class user(frontend.Object): """ @@ -68,30 +86,30 @@ class user(frontend.Object): normalize=lambda value: value.lower(), ), Param('gecos?', - doc='Set the GECOS field', + doc='GECOS field', default_from=lambda uid: uid, ), Param('homedirectory?', cli_name='home', - doc='Set the User\'s home directory', + doc='User\'s home directory', default_from=lambda uid: '/home/%s' % uid, ), Param('loginshell?', cli_name='shell', default=u'/bin/sh', - doc='Set User\'s Login shell', + doc='User\'s Login shell', ), Param('krbprincipalname?', cli_name='principal', - doc='Set User\'s Kerberos Principal name', + doc='User\'s Kerberos Principal name', default_from=lambda uid: '%s@%s' % (uid, api.env.realm), ), Param('mailaddress?', cli_name='mail', - doc='Set User\'s e-mail address', + doc='User\'s e-mail address', ), Param('userpassword?', cli_name='password', - doc='Set User\'s password', + doc='User\'s password', ), Param('groups?', doc='Add account to one or more groups (comma-separated)', @@ -248,6 +266,9 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' + takes_options = ( + Param('all?', type=ipa_types.Bool(), doc='Retrieve all user attributes'), + ) def execute(self, term, **kw): ldap = self.api.Backend.ldap @@ -262,6 +283,10 @@ class user_find(crud.Find): object_type = ldap.get_object_type("uid") if object_type and not kw.get('objectclass'): kw['objectclass'] = object_type + if kw.get('all', False): + kw['attributes'] = ['*'] + else: + kw['attributes'] = default_attributes return ldap.search(**kw) def output_for_cli(self, users): if not users: @@ -276,15 +301,15 @@ class user_find(crud.Find): print "Please refine your search and try again." for u in users: - for a in u.keys(): - print "%s: %s" % (a, u[a]) + display_user(u) + print "" api.register(user_find) class user_show(crud.Get): 'Examine an existing user.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Display all user attributes'), + Param('all?', type=ipa_types.Bool(), doc='Retrieve all user attributes'), ) def execute(self, uid, **kw): """ @@ -304,11 +329,10 @@ class user_show(crud.Get): if kw.get('all', False): return ldap.retrieve(dn) else: - return ldap.retrieve(dn, ['uid','givenname','sn','homeDirectory','loginshell']) + return ldap.retrieve(dn, default_attributes) def output_for_cli(self, user): if user: - for a in user.keys(): - print "%s: %s" % (a, user[a]) + display_user(user) api.register(user_show) -- cgit From 6a8026f974c4ab65313729eb9e61303b5395a0c0 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 24 Oct 2008 11:39:47 -0400 Subject: If a password is supplied then this host will be bulk-enrolled A bulk-enrolled host does not get a kerberos service principal until enrollment time. --- ipalib/plugins/f_host.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py index da281548..4f4f7204 100644 --- a/ipalib/plugins/f_host.py +++ b/ipalib/plugins/f_host.py @@ -103,6 +103,9 @@ class host_add(crud.Add): The dn should not be passed as a keyword argument as it is constructed by this method. + If password is set then this is considered a 'bulk' host so we + do not create a kerberos service principal. + Returns the entry as it will be created in LDAP. :param hostname: The name of the host being added. @@ -110,27 +113,39 @@ class host_add(crud.Add): """ assert 'cn' not in kw assert 'dn' not in kw + assert 'krbprincipalname' not in kw ldap = self.api.Backend.ldap kw['cn'] = hostname kw['serverhostname'] = hostname.split('.',1)[0] kw['dn'] = ldap.make_host_dn(hostname) - kw['krbPrincipalName'] = "host/%s@%s" % (hostname, self.api.env.realm) # FIXME: do a DNS lookup to ensure host exists current = util.get_current_principal() if not current: raise errors.NotFound('Unable to determine current user') - kw['enrolledBy'] = ldap.find_entry_dn("krbPrincipalName", current, "person") + kw['enrolledby'] = ldap.find_entry_dn("krbPrincipalName", current, "posixAccount") # Get our configuration config = ldap.get_ipa_config() # some required objectclasses # FIXME: add this attribute to cn=ipaconfig - #kw['objectClass'] = config.get('ipahostobjectclasses') - kw['objectClass'] = ['nsHost', 'krbPrincipalAux', 'ipaHost'] + #kw['objectclass'] = config.get('ipahostobjectclasses') + kw['objectclass'] = ['nsHost', 'ipaHost'] + + # Ensure the list of objectclasses is lower-case + kw['objectclass'] = map(lambda z: z.lower(), kw.get('objectclass')) + + if not kw.get('userpassword', False): + kw['krbprincipalname'] = "host/%s@%s" % (hostname, self.api.env.realm) + + if 'krbprincipalaux' not in kw.get('objectclass'): + kw['objectclass'].append('krbprincipalaux') + else: + if 'krbprincipalaux' in kw.get('objectclass'): + kw['objectclass'].remove('krbprincipalaux') return ldap.create(**kw) def output_for_cli(self, ret): -- cgit From 8788afe18403e7585e4fc2b6a52a352a035fee0b Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 24 Oct 2008 11:40:47 -0400 Subject: Use posixAccount instead of person to identify users Add output_for_cli to service-find --- ipalib/plugins/f_passwd.py | 2 +- ipalib/plugins/f_service.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py index f70eacac..7b424a3b 100644 --- a/ipalib/plugins/f_passwd.py +++ b/ipalib/plugins/f_passwd.py @@ -60,7 +60,7 @@ class passwd(frontend.Command): else: principal = principal - dn = ldap.find_entry_dn("krbprincipalname", principal, "person") + dn = ldap.find_entry_dn("krbprincipalname", principal, "posixAccount") # FIXME: we need a way to prompt for passwords using getpass kw['newpass'] = "password" diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index 38c80ad2..9e9cec53 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -110,7 +110,7 @@ class service_add(crud.Add): def output_to_cli(self, ret): if ret: - print "Service added" + print "Service added" api.register(service_add) @@ -146,7 +146,7 @@ class service_find(crud.Find): def execute(self, principal, **kw): ldap = self.api.Backend.ldap - kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=person))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" + kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=posixAccount))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" kw['krbprincipalname'] = principal object_type = ldap.get_object_type("krbprincipalname") @@ -193,5 +193,11 @@ class service_show(crud.Get): dn = ldap.find_entry_dn("krbprincipalname", principal) # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) + def output_for_cli(self, service): + if not service: + return + + for a in service.keys(): + print "%s: %s" % (a, service[a]) api.register(service_show) -- cgit From 34520981eeaac5d4f37915509a9e26428e26f5c0 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 24 Oct 2008 14:17:20 -0400 Subject: Don't allow service-add to create host/ principals --- ipalib/plugins/f_service.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index 9e9cec53..f02176ff 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -72,6 +72,9 @@ class service_add(crud.Add): raise errors.MalformedServicePrincipal service = sp[0] + if service.lower() == "host": + raise errors.HostService + sr = sp[1].split('@') if len(sr) == 1: hostname = sr[0].lower() -- cgit From 201a963930b69baff2a31f685cb4cdd38d6da42e Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 27 Oct 2008 12:23:49 -0400 Subject: Fix comment --- ipalib/plugins/f_group.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index b5f80f93..13af14c1 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -135,7 +135,7 @@ class group_mod(crud.Mod): 'Edit an existing group.' def execute(self, cn, **kw): """ - Execute the user-mod operation. + Execute the group-mod operation. The dn should not be passed as a keyword argument as it is constructed by this method. -- cgit From 54f37503d2076b99b3b7479b19fec4fa17bc7c59 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 27 Oct 2008 12:24:17 -0400 Subject: Implement host groups --- ipalib/plugins/f_hostgroup.py | 328 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 ipalib/plugins/f_hostgroup.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_hostgroup.py b/ipalib/plugins/f_hostgroup.py new file mode 100644 index 00000000..27aea00c --- /dev/null +++ b/ipalib/plugins/f_hostgroup.py @@ -0,0 +1,328 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for groups of hosts +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api +from ipalib import errors +from ipalib import ipa_types + +hostgroup_filter = "groupofnames)(!(objectclass=posixGroup)" + +class hostgroup(frontend.Object): + """ + Host Group object. + """ + takes_params = ( + Param('description', + doc='A description of this group', + ), + Param('cn', + cli_name='name', + primary_key=True, + normalize=lambda value: value.lower(), + ) + ) +api.register(hostgroup) + + +class hostgroup_add(crud.Add): + 'Add a new group of hosts.' + + def execute(self, cn, **kw): + """ + Execute the hostgroup-add operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry as it will be created in LDAP. + + No need to explicitly set gidNumber. The dna_plugin will do this + for us if the value isn't provided by the caller. + + :param cn: The name of the host group being added. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + kw['cn'] = cn + kw['dn'] = ldap.make_hostgroup_dn(cn) + + # Get our configuration + #config = ldap.get_ipa_config() + + # some required objectclasses + # FIXME: get this out of config + kw['objectClass'] = ['groupofnames'] + + return ldap.create(**kw) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Group added" + +api.register(hostgroup_add) + + +class hostgroup_del(crud.Del): + 'Delete an existing group of hosts.' + def execute(self, cn, **kw): + """ + Delete a group of hosts + + The memberOf plugin handles removing the group from any other + groups. + + :param cn: The name of the group being removed + :param kw: Unused + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) + + return ldap.delete(dn) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Group deleted" + +api.register(hostgroup_del) + + +class hostgroup_mod(crud.Mod): + 'Edit an existing group of hosts.' + def execute(self, cn, **kw): + """ + Execute the hostgroup-mod operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param cn: The name of the group to update. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) + return ldap.update(dn, **kw) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Group updated" + +api.register(hostgroup_mod) + + +class hostgroup_find(crud.Find): + 'Search the groups of hosts.' + def execute(self, term, **kw): + ldap = self.api.Backend.ldap + + # Pull the list of searchable attributes out of the configuration. + config = ldap.get_ipa_config() + + # FIXME: for now use same search fields as user groups + search_fields_conf_str = config.get('ipagroupsearchfields') + search_fields = search_fields_conf_str.split(",") + + for s in search_fields: + kw[s] = term + + kw['objectclass'] = hostgroup_filter + return ldap.search(**kw) + + def output_for_cli(self, groups): + if not groups: + return + + counter = groups[0] + groups = groups[1:] + if counter == 0: + print "No entries found" + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for g in groups: + for a in g.keys(): + print "%s: %s" % (a, g[a]) + +api.register(hostgroup_find) + + +class hostgroup_show(crud.Get): + 'Examine an existing group of hosts.' + def execute(self, cn, **kw): + """ + Execute the hostgroup-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param cn: The group name to retrieve. + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + # FIXME: this works for now but the plan is to add a new objectclass + # type. + dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) + # FIXME: should kw contain the list of attributes to display? + return ldap.retrieve(dn) + + def output_for_cli(self, group): + if not group: + return + + for a in group.keys(): + print "%s: %s" % (a, group[a]) + +api.register(hostgroup_show) + + +class hostgroup_add_member(frontend.Command): + 'Add a member to a group.' + takes_args = ( + Param('group', primary_key=True), + ) + takes_options = ( + Param('groups?', doc='comma-separated list of groups to add'), + ) + def execute(self, cn, **kw): + """ + Execute the hostgroup-add-member operation. + + Returns the updated group entry + + :param cn: The group name to add new members to. + :param kw: groups is a comma-separated list of groups to add + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) + add_failed = [] + to_add = [] + completed = 0 + + members = kw.get('groups', '').split(',') + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn("cn", m, hostgroup_filter) + to_add.append(member_dn) + except errors.NotFound: + add_failed.append(m) + continue + + for member_dn in to_add: + try: + ldap.add_member_to_group(member_dn, dn) + completed+=1 + except: + add_failed.append(member_dn) + + return add_failed + + def output_for_cli(self, add_failed): + """ + Output result of this command to command line interface. + """ + if add_failed: + print "These entries failed to add to the group:" + for a in add_failed: + print "\t'%s'" % a + else: + print "Group membership updated." + +api.register(hostgroup_add_member) + + +class hostgroup_remove_member(frontend.Command): + 'Remove a member from a group.' + takes_args = ( + Param('group', primary_key=True), + ) + takes_options = ( + Param('groups?', doc='comma-separated list of groups to remove'), + ) + def execute(self, cn, **kw): + """ + Execute the group-remove-member operation. + + Returns the members that could not be added + + :param cn: The group name to add new members to. + :param kw: groups is a comma-separated list of groups to remove + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) + to_remove = [] + remove_failed = [] + completed = 0 + + members = kw.get('groups', '').split(',') + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn("cn", m, hostgroup_filter) + to_remove.append(member_dn) + except errors.NotFound: + remove_failed.append(m) + continue + + for member_dn in to_remove: + try: + ldap.remove_member_from_group(member_dn, dn) + completed+=1 + except: + remove_failed.append(member_dn) + + return remove_failed + + def output_for_cli(self, remove_failed): + """ + Output result of this command to command line interface. + """ + if remove_failed: + print "These entries failed to be removed from the group:" + for a in remove_failed: + print "\t'%s'" % a + else: + print "Group membership updated." + +api.register(hostgroup_remove_member) -- cgit From 2307d4ddd0409f00511c4d83ad7dab5e9d6d96df Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 27 Oct 2008 23:56:22 -0600 Subject: Fixed use of depreciated env.get() in b_xmlrpc.py module --- ipalib/plugins/b_xmlrpc.py | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 572a7511..2c98fb8a 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -36,23 +36,26 @@ from ipalib import errors class xmlrpc(Backend): """ - Kerberos backend plugin. + XML-RPC client backend plugin. """ - def get_client(self, verbose=False): - # FIXME: The server uri should come from self.api.env.server_uri - if api.env.get('kerberos'): - server = api.env.server.next() - if verbose: print "Connecting to %s" % server - return xmlrpclib.ServerProxy('https://%s/ipa/xml' % server, transport=KerbTransport(), verbose=verbose) - else: - return xmlrpclib.ServerProxy('http://localhost:8888', verbose=verbose) + def get_client(self): + """ + Return an xmlrpclib.ServerProxy instance (the client). + """ + uri = self.api.env.xmlrpc_uri + if uri.startswith('https://'): + return xmlrpclib.ServerProxy(uri, + transport=KerbTransport(), + verbose=self.api.env.verbose, + ) + return xmlrpclib.ServerProxy(uri, verbose=self.api.env.verbose) def forward_call(self, name, *args, **kw): """ Forward a call over XML-RPC to an IPA server. """ - client = self.get_client(verbose=api.env.get('verbose', False)) + client = self.get_client() command = getattr(client, name) params = xmlrpc_marshal(*args, **kw) try: -- cgit From 6879140db790a23a8782f7200400f2b58a69f6a0 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Thu, 30 Oct 2008 02:20:28 -0600 Subject: Added ipalib.plugins.f_misc with new 'context' Command; moved 'env' Command from cli to f_misc --- ipalib/plugins/f_misc.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 ipalib/plugins/f_misc.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_misc.py b/ipalib/plugins/f_misc.py new file mode 100644 index 00000000..ff8569b1 --- /dev/null +++ b/ipalib/plugins/f_misc.py @@ -0,0 +1,73 @@ +# Authors: +# Jason Gerard DeRose +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Misc frontend plugins. +""" + +from ipalib import api, Command, Param, Bool + + +class env_and_context(Command): + """ + Base class for `env` and `context` commands. + """ + + def run(self, **kw): + if kw.get('server', False) and not self.api.env.in_server: + return self.forward() + return self.execute() + + def output_for_cli(self, ret): + for (key, value) in ret: + print '%s = %r' % (key, value) + + +class env(env_and_context): + """Show environment variables""" + + takes_options = ( + Param('server?', type=Bool(), default=False, + doc='Show environment variables of server', + ), + ) + + def execute(self): + return tuple( + (key, self.api.env[key]) for key in self.api.env + ) + +api.register(env) + + +class context(env_and_context): + """Show request context""" + + takes_options = ( + Param('server?', type=Bool(), default=False, + doc='Show request context in server', + ), + ) + + def execute(self): + return [ + (key, self.api.context[key]) for key in self.api.Context + ] + +api.register(context) -- cgit From 62876ccee3ba679adda926b88564732552459619 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 30 Oct 2008 17:25:45 -0400 Subject: Initial implementation of automount support Add argument handling to crud.Del Make get_list handle LDAP scope --- ipalib/plugins/f_automount.py | 472 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 ipalib/plugins/f_automount.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py new file mode 100644 index 00000000..78e96ccd --- /dev/null +++ b/ipalib/plugins/f_automount.py @@ -0,0 +1,472 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2008 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for automount. + +RFC 2707bis http://www.padl.com/~lukeh/rfc2307bis.txt +""" + +from ipalib import frontend +from ipalib import crud +from ipalib.frontend import Param +from ipalib import api +from ipalib import errors +from ipalib import ipa_types +from ldap import explode_dn + +map_attributes = ['automountMapName', 'description', ] +key_attributes = ['description', 'automountKey', 'automountInformation'] + +def display_entry(entry): + # FIXME: for now delete dn here. In the future pass in the kw to + # output_for_cli() + attr = sorted(entry.keys()) + + for a in attr: + if a != 'dn': + print "%s: %s" % (a, entry[a]) + +def make_automount_dn(mapname): + """ + Construct automount dn from map name. + """ + # FIXME, should this be in b_ldap? + # Experimenting to see what a plugin looks like for a 3rd party who can't + # modify the backend. + import ldap + return 'automountmapname=%s,%s,%s' % ( + ldap.dn.escape_dn_chars(mapname), + api.env.container_accounts, + api.env.basedn, + ) + +class automount(frontend.Object): + """ + Automount object. + """ + takes_params = ( + Param('automountmapname', + cli_name='mapname', + primary_key=True, + doc='A group of related automount objects', + ), + ) +api.register(automount) + + +class automount_addmap(crud.Add): + 'Add a new automount map.' + takes_options = ( + Param('description?', + doc='A description of the automount map'), + ) + + def execute(self, mapname, **kw): + """ + Execute the automount-addmap operation. + + Returns the entry as it will be created in LDAP. + + :param mapname: The map name being added. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + kw['automountmapname'] = mapname + kw['dn'] = make_automount_dn(mapname) + + kw['objectClass'] = ['automountMap'] + + return ldap.create(**kw) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Automount map added" + +api.register(automount_addmap) + + +class automount_addkey(crud.Add): + 'Add a new automount key.' + takes_options = ( + Param('automountkey', + cli_name='key', + doc='An entry in an automount map'), + Param('automountinformation', + cli_name='info', + doc='Mount information for this key'), + Param('description?', + doc='A description of the mount'), + ) + + def execute(self, mapname, **kw): + """ + Execute the automount-addkey operation. + + Returns the entry as it will be created in LDAP. + + :param mapname: The map name being added to. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + # use find_entry_dn instead of make_automap_dn so we can confirm that + # the map exists + map_dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + kw['dn'] = "automountkey=%s,%s" % (kw['automountkey'], map_dn) + + kw['objectClass'] = ['automount'] + + return ldap.create(**kw) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Automount key added" + +api.register(automount_addkey) + + +class automount_delmap(crud.Del): + 'Delete an automount map.' + def execute(self, mapname, **kw): + """Delete an automount map. This will also remove all of the keys + associated with this map. + + mapname is the automount map to remove + + :param mapname: The map to be removed + :param kw: Not used. + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + keys = api.Command['automount_getkeys'](mapname) + if keys: + for k in keys: + ldap.delete(k.get('dn')) + return ldap.delete(dn) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Automount map and associated keys deleted" + +api.register(automount_delmap) + + +class automount_delkey(crud.Del): + 'Delete an automount key.' + takes_options = ( + Param('key', + doc='The automount key to remove'), + ) + def execute(self, mapname, **kw): + """Delete an automount key. + + key is the automount key to remove + + :param mapname: The automount map containing the key to be removed + :param kw: "key" the key to be removed + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + keys = api.Command['automount_getkeys'](mapname) + keydn = None + keyname = kw.get('key').lower() + if keys: + for k in keys: + if k.get('automountkey').lower() == keyname: + keydn = k.get('dn') + break + if not keydn: + raise errors.NotFound + return ldap.delete(keydn) + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Automount key deleted" + +api.register(automount_delkey) + +class automount_modmap(crud.Mod): + 'Edit an existing automount map.' + takes_options = ( + Param('description?', + doc='A description of the automount map'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-modmap operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param mapname: The map name to update. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + return ldap.update(dn, **kw) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Automount map updated" + +api.register(automount_modmap) + + +class automount_modkey(crud.Mod): + 'Edit an existing automount key.' + takes_options = ( + Param('automountkey', + cli_name='key', + doc='An entry in an automount map'), + Param('automountinformation?', + cli_name='info', + doc='Mount information for this key'), + Param('description?', + doc='A description of the automount map'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-modkey operation. + + Returns the entry + + :param mapname: The map name to update. + :param kw: Keyword arguments for the other LDAP attributes. + """ + assert 'automountmapname' not in kw + assert 'dn' not in kw + keyname = kw.get('automountkey').lower() + del kw['automountkey'] + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + keys = api.Command['automount_getkeys'](mapname) + keydn = None + if keys: + for k in keys: + if k.get('automountkey').lower() == keyname: + keydn = k.get('dn') + break + if not keydn: + raise errors.NotFound + return ldap.update(keydn, **kw) + + def output_for_cli(self, ret): + """ + Output result of this command to command line interface. + """ + if ret: + print "Automount key updated" +api.register(automount_modkey) + + +class automount_findmap(crud.Find): + 'Search automount maps.' + takes_options = ( + Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + ) + def execute(self, term, **kw): + ldap = self.api.Backend.ldap + + search_fields = map_attributes + + for s in search_fields: + kw[s] = term + + kw['objectclass'] = 'automountMap' + if kw.get('all', False): + kw['attributes'] = ['*'] + else: + kw['attributes'] = map_attributes + return ldap.search(**kw) + def output_for_cli(self, entries): + if not entries: + return + counter = entries[0] + entries = entries[1:] + if counter == 0: + print "No entries found" + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for e in entries: + display_entry(e) + print "" +api.register(automount_findmap) + + +class automount_findkey(crud.Find): + 'Search automount keys.' + takes_options = ( + Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + ) + def execute(self, term, **kw): + ldap = self.api.Backend.ldap + + search_fields = key_attributes + + for s in search_fields: + kw[s] = term + + kw['objectclass'] = 'automount' + if kw.get('all', False): + kw['attributes'] = ['*'] + else: + kw['attributes'] = key_attributes + return ldap.search(**kw) + def output_for_cli(self, entries): + if not entries: + return + counter = entries[0] + entries = entries[1:] + if counter == 0: + print "No entries found" + return + elif counter == -1: + print "These results are truncated." + print "Please refine your search and try again." + + for e in entries: + display_entry(e) + print "" +api.register(automount_findkey) + + +class automount_showmap(crud.Get): + 'Examine an existing automount map.' + takes_options = ( + Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-showmap operation. + + Returns the entry + + :param mapname: The automount map to retrieve + :param kw: "all" set to True = return all attributes + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + # FIXME: should kw contain the list of attributes to display? + if kw.get('all', False): + return ldap.retrieve(dn) + else: + return ldap.retrieve(dn, map_attributes) + def output_for_cli(self, entry): + if entry: + display_entry(entry) + +api.register(automount_showmap) + + +class automount_showkey(crud.Get): + 'Examine an existing automount key.' + takes_options = ( + Param('key', + doc='The automount key to display'), + Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-showkey operation. + + Returns the entry + + :param mapname: The mapname to examine + :param kw: "key" the key to retrieve + :param kw: "all" set to True = return all attributes + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + keys = api.Command['automount_getkeys'](mapname) + keyname = kw.get('key').lower() + keydn = None + if keys: + for k in keys: + if k.get('automountkey').lower() == keyname: + keydn = k.get('dn') + break + if not keydn: + raise errors.NotFound + # FIXME: should kw contain the list of attributes to display? + if kw.get('all', False): + return ldap.retrieve(keydn) + else: + return ldap.retrieve(keydn, key_attributes) + def output_for_cli(self, entry): + # The automount map name associated with this key is available only + # in the dn. Add it as an attribute to display instead. + if entry and not entry.get('automountmapname'): + elements = explode_dn(entry.get('dn').lower()) + for e in elements: + (attr, value) = e.split('=',1) + if attr == 'automountmapname': + entry['automountmapname'] = value + display_entry(entry) + +api.register(automount_showkey) + + +class automount_getkeys(frontend.Command): + 'Retrieve all keys for an automount map.' + takes_args = ( + Param('automountmapname', + cli_name='mapname', + primary_key=True, + doc='A group of related automount objects', + ), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-getkeys operation. + + Return a list of all automount keys for this mapname + + :param mapname: Retrieve all keys for this mapname + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + return ldap.get_one_entry(dn, 'objectclass=*', ['automountkey']) + def output_for_cli(self, keys): + if keys: + for k in keys: + print k.get('automountkey') + +api.register(automount_getkeys) -- cgit From dd9206deb62c1c96344d2280f672353a53a7fd11 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 31 Oct 2008 17:03:10 -0400 Subject: Uncomment some logging statements ported over from v1. --- ipalib/plugins/f_group.py | 2 +- ipalib/plugins/f_service.py | 4 ++-- ipalib/plugins/f_user.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index 13af14c1..9df83a29 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -111,7 +111,7 @@ class group_del(crud.Del): ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("cn", cn, "posixGroup") -# logging.info("IPA: delete_group '%s'" % dn) + self.log.info("IPA: group-del '%s'" % dn) # Don't allow the default user group to be removed config=ldap.get_ipa_config() diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index f02176ff..04187a86 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -91,10 +91,10 @@ class service_add(crud.Add): fqdn = hostname + "." rs = dnsclient.query(fqdn, dnsclient.DNS_C_IN, dnsclient.DNS_T_A) if len(rs) == 0: - logging.debug("IPA: DNS A record lookup failed for '%s'" % hostname) + self.log.debug("IPA: DNS A record lookup failed for '%s'" % hostname) raise ipaerror.gen_exception(ipaerror.INPUT_NOT_DNS_A_RECORD) else: - logging.debug("IPA: found %d records for '%s'" % (len(rs), hostname)) + self.log.debug("IPA: found %d records for '%s'" % (len(rs), hostname)) """ # At some point we'll support multiple realms diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index d8bb49e2..3adb328c 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -219,7 +219,7 @@ class user_del(crud.Del): # FIXME: do we still want a "special" user? raise SyntaxError("admin required") # raise ipaerror.gen_exception(ipaerror.INPUT_ADMIN_REQUIRED) -# logging.info("IPA: delete_user '%s'" % uid) + self.log.info("IPA: user-del '%s'" % uid) ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("uid", uid) -- cgit From d53218a9321eb4def0bfeb484709323de74eef1a Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 3 Nov 2008 17:19:29 -0500 Subject: Handle exceptions in the command-line instead of in the XMLRPC client plugin --- ipalib/plugins/b_xmlrpc.py | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 2c98fb8a..9c6af0a0 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -64,14 +64,7 @@ class xmlrpc(Backend): print e[1] except xmlrpclib.Fault, e: err = errors.convertFault(e) - code = getattr(err,'faultCode',None) - faultString = getattr(err,'faultString',None) - if not code: - raise err - if code < errors.IPA_ERROR_BASE: - print "%s: %s" % (code, faultString) - else: - print "%s: %s" % (code, getattr(err,'__doc__','')) + raise err return api.register(xmlrpc) -- cgit From f1314806434b9226f8a7722675b060bdf574c455 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 3 Nov 2008 17:38:05 -0500 Subject: Move socket errors from the XML-RPC plugin to the client --- ipalib/plugins/b_xmlrpc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 9c6af0a0..87dc9505 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -61,7 +61,7 @@ class xmlrpc(Backend): try: return command(*params) except socket.error, e: - print e[1] + raise except xmlrpclib.Fault, e: err = errors.convertFault(e) raise err -- cgit From 49670023591f8eb88dd5860fffc3f8e99764e5a8 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 4 Nov 2008 14:02:42 -0500 Subject: Add 'all' option to host-find and pull attributes into a global list --- ipalib/plugins/f_host.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py index 4f4f7204..e842230f 100644 --- a/ipalib/plugins/f_host.py +++ b/ipalib/plugins/f_host.py @@ -55,6 +55,7 @@ def validate_host(cn): return 'Fully-qualified hostname required' return None +default_attributes = ['cn','description','localityname','nshostlocation','nshardwareplatform','nsosversion'] class host(frontend.Object): """ @@ -213,6 +214,9 @@ api.register(host_mod) class host_find(crud.Find): 'Search the hosts.' + takes_options = ( + Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + ) def get_args(self): """ Override Find.get_args() so we can exclude the validation rules @@ -233,6 +237,10 @@ class host_find(crud.Find): # Can't use ldap.get_object_type() since cn is also used for group dns kw['objectclass'] = "ipaHost" + if kw.get('all', False): + kw['attributes'] = ['*'] + else: + kw['attributes'] = default_attributes return ldap.search(**kw) def output_for_cli(self, hosts): if not hosts: @@ -275,7 +283,7 @@ class host_show(crud.Get): if kw.get('all', False): return ldap.retrieve(dn) else: - value = ldap.retrieve(dn, ['cn','description','localityname','nshostlocation','nshardwareplatform','nsosversion']) + value = ldap.retrieve(dn, default_attributes) del value['dn'] return value def output_for_cli(self, host): -- cgit From e825bc7ccbc787e65efa7171e9f19793bcd88615 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 4 Nov 2008 14:03:43 -0500 Subject: Revive the hostgroup_container and include add/remove hosts in hostgroups plugin --- ipalib/plugins/f_hostgroup.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_hostgroup.py b/ipalib/plugins/f_hostgroup.py index 27aea00c..8e4c3740 100644 --- a/ipalib/plugins/f_hostgroup.py +++ b/ipalib/plugins/f_hostgroup.py @@ -222,7 +222,8 @@ class hostgroup_add_member(frontend.Command): Param('group', primary_key=True), ) takes_options = ( - Param('groups?', doc='comma-separated list of groups to add'), + Param('groups?', doc='comma-separated list of host groups to add'), + Param('hosts?', doc='comma-separated list of hosts to add'), ) def execute(self, cn, **kw): """ @@ -231,7 +232,8 @@ class hostgroup_add_member(frontend.Command): Returns the updated group entry :param cn: The group name to add new members to. - :param kw: groups is a comma-separated list of groups to add + :param kw: groups is a comma-separated list of host groups to add + :param kw: hosts is a comma-separated list of hosts to add """ ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) @@ -249,6 +251,16 @@ class hostgroup_add_member(frontend.Command): add_failed.append(m) continue + members = kw.get('hosts', '').split(',') + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn("cn", m, "ipaHost") + to_add.append(member_dn) + except errors.NotFound: + add_failed.append(m) + continue + for member_dn in to_add: try: ldap.add_member_to_group(member_dn, dn) @@ -278,6 +290,7 @@ class hostgroup_remove_member(frontend.Command): Param('group', primary_key=True), ) takes_options = ( + Param('hosts?', doc='comma-separated list of hosts to add'), Param('groups?', doc='comma-separated list of groups to remove'), ) def execute(self, cn, **kw): @@ -288,6 +301,7 @@ class hostgroup_remove_member(frontend.Command): :param cn: The group name to add new members to. :param kw: groups is a comma-separated list of groups to remove + :param kw: hosts is a comma-separated list of hosts to add """ ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) @@ -305,6 +319,16 @@ class hostgroup_remove_member(frontend.Command): remove_failed.append(m) continue + members = kw.get('hosts', '').split(',') + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn("cn", m, "ipaHost") + to_remove.append(member_dn) + except errors.NotFound: + remove_failed.append(m) + continue + for member_dn in to_remove: try: ldap.remove_member_from_group(member_dn, dn) -- cgit From e8adb59fd42eddb9f8911f6d888d9a64e0773df9 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Tue, 4 Nov 2008 16:21:10 -0500 Subject: Fix some problems uncovered during automation test work --- ipalib/plugins/f_automount.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py index 78e96ccd..fba9e12c 100644 --- a/ipalib/plugins/f_automount.py +++ b/ipalib/plugins/f_automount.py @@ -180,7 +180,8 @@ api.register(automount_delmap) class automount_delkey(crud.Del): 'Delete an automount key.' takes_options = ( - Param('key', + Param('automountkey', + cli_name='key', doc='The automount key to remove'), ) def execute(self, mapname, **kw): @@ -195,7 +196,7 @@ class automount_delkey(crud.Del): dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") keys = api.Command['automount_getkeys'](mapname) keydn = None - keyname = kw.get('key').lower() + keyname = kw.get('automountkey').lower() if keys: for k in keys: if k.get('automountkey').lower() == keyname: @@ -336,6 +337,10 @@ class automount_findkey(crud.Find): takes_options = ( Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), ) + def get_args(self): + return (Param('automountkey', + cli_name='key', + doc='An entry in an automount map'),) def execute(self, term, **kw): ldap = self.api.Backend.ldap @@ -399,7 +404,8 @@ api.register(automount_showmap) class automount_showkey(crud.Get): 'Examine an existing automount key.' takes_options = ( - Param('key', + Param('automountkey', + cli_name='key', doc='The automount key to display'), Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), ) @@ -410,13 +416,13 @@ class automount_showkey(crud.Get): Returns the entry :param mapname: The mapname to examine - :param kw: "key" the key to retrieve + :param kw: "automountkey" the key to retrieve :param kw: "all" set to True = return all attributes """ ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") keys = api.Command['automount_getkeys'](mapname) - keyname = kw.get('key').lower() + keyname = kw.get('automountkey').lower() keydn = None if keys: for k in keys: @@ -463,7 +469,12 @@ class automount_getkeys(frontend.Command): """ ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") - return ldap.get_one_entry(dn, 'objectclass=*', ['automountkey']) + try: + keys = ldap.get_one_entry(dn, 'objectclass=*', ['automountkey']) + except errors.NotFound: + keys = [] + + return keys def output_for_cli(self, keys): if keys: for k in keys: -- cgit From 014af24731ff39520a9635694ed99dc9d09669c9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 12 Nov 2008 00:46:04 -0700 Subject: Changed calling signature of output_for_cli(); started work on 'textui' backend plugin --- ipalib/plugins/f_misc.py | 48 +++++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_misc.py b/ipalib/plugins/f_misc.py index ff8569b1..055e54d7 100644 --- a/ipalib/plugins/f_misc.py +++ b/ipalib/plugins/f_misc.py @@ -24,22 +24,11 @@ Misc frontend plugins. from ipalib import api, Command, Param, Bool -class env_and_context(Command): - """ - Base class for `env` and `context` commands. - """ - - def run(self, **kw): - if kw.get('server', False) and not self.api.env.in_server: - return self.forward() - return self.execute() - - def output_for_cli(self, ret): - for (key, value) in ret: - print '%s = %r' % (key, value) - - -class env(env_and_context): +# FIXME: We should not let env return anything in_server +# when mode == 'production'. This would allow an attacker to see the +# configuration of the server, potentially revealing compromising +# information. However, it's damn handy for testing/debugging. +class env(Command): """Show environment variables""" takes_options = ( @@ -48,26 +37,19 @@ class env(env_and_context): ), ) + def run(self, **kw): + if kw.get('server', False) and not self.api.env.in_server: + return self.forward() + return self.execute() + def execute(self): return tuple( (key, self.api.env[key]) for key in self.api.env ) -api.register(env) - - -class context(env_and_context): - """Show request context""" - - takes_options = ( - Param('server?', type=Bool(), default=False, - doc='Show request context in server', - ), - ) - - def execute(self): - return [ - (key, self.api.context[key]) for key in self.api.Context - ] + def output_for_cli(self, textui, result, **kw): + textui.print_name(self.name) + textui.print_keyval(result) + textui.print_count(result, '%d variable', '%d variables') -api.register(context) +api.register(env) -- cgit From 09161e399a61e2a548e9efb3c3abb2c7b47d5520 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 12 Nov 2008 01:47:37 -0700 Subject: Command.get_default() will now fill-in None for all missing non-required params --- ipalib/plugins/b_xmlrpc.py | 4 ++++ ipalib/plugins/f_misc.py | 27 +++++++++++++++++++-------- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 87dc9505..22361b1b 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -43,6 +43,10 @@ class xmlrpc(Backend): """ Return an xmlrpclib.ServerProxy instance (the client). """ + # FIXME: Rob, is there any reason we can't use allow_none=True here? + # Are there any reasonably common XML-RPC client implementations + # that don't support the extension? + # See: http://docs.python.org/library/xmlrpclib.html uri = self.api.env.xmlrpc_uri if uri.startswith('https://'): return xmlrpclib.ServerProxy(uri, diff --git a/ipalib/plugins/f_misc.py b/ipalib/plugins/f_misc.py index 055e54d7..1acf1c99 100644 --- a/ipalib/plugins/f_misc.py +++ b/ipalib/plugins/f_misc.py @@ -31,23 +31,34 @@ from ipalib import api, Command, Param, Bool class env(Command): """Show environment variables""" + takes_args = ('variables*',) + takes_options = ( Param('server?', type=Bool(), default=False, doc='Show environment variables of server', ), ) - def run(self, **kw): - if kw.get('server', False) and not self.api.env.in_server: - return self.forward() - return self.execute() + def run(self, variables, **kw): + if kw['server'] and not self.env.in_server: + return self.forward(variables) + return self.execute(variables) + + def find_keys(self, variables): + for key in variables: + if key in self.env: + yield (key, self.env[key]) - def execute(self): - return tuple( - (key, self.api.env[key]) for key in self.api.env - ) + def execute(self, variables): + if variables is None: + return tuple( + (key, self.env[key]) for key in self.env + ) + return tuple(self.find_keys(variables)) def output_for_cli(self, textui, result, **kw): + if len(result) == 0: + return textui.print_name(self.name) textui.print_keyval(result) textui.print_count(result, '%d variable', '%d variables') -- cgit From f04aaff97c9c8c22b36706f2c6d4de6f23d06b95 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 12 Nov 2008 09:55:11 -0700 Subject: output_for_cli signature is now output_for_cli(textui, result, *args, **options) --- ipalib/plugins/f_misc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_misc.py b/ipalib/plugins/f_misc.py index 1acf1c99..05fd6d52 100644 --- a/ipalib/plugins/f_misc.py +++ b/ipalib/plugins/f_misc.py @@ -39,8 +39,8 @@ class env(Command): ), ) - def run(self, variables, **kw): - if kw['server'] and not self.env.in_server: + def run(self, variables, **options): + if options['server'] and not self.env.in_server: return self.forward(variables) return self.execute(variables) @@ -56,7 +56,7 @@ class env(Command): ) return tuple(self.find_keys(variables)) - def output_for_cli(self, textui, result, **kw): + def output_for_cli(self, textui, result, variables, **options): if len(result) == 0: return textui.print_name(self.name) -- cgit From c513743e7c9a611d0b3b0abaf13b79d6237ed6da Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 14 Nov 2008 18:04:57 -0500 Subject: Add autmount-specific location and default entries --- ipalib/plugins/f_automount.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py index fba9e12c..7a251572 100644 --- a/ipalib/plugins/f_automount.py +++ b/ipalib/plugins/f_automount.py @@ -53,7 +53,7 @@ def make_automount_dn(mapname): import ldap return 'automountmapname=%s,%s,%s' % ( ldap.dn.escape_dn_chars(mapname), - api.env.container_accounts, + api.env.container_automount, api.env.basedn, ) @@ -133,7 +133,7 @@ class automount_addkey(crud.Add): ldap = self.api.Backend.ldap # use find_entry_dn instead of make_automap_dn so we can confirm that # the map exists - map_dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + map_dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) kw['dn'] = "automountkey=%s,%s" % (kw['automountkey'], map_dn) kw['objectClass'] = ['automount'] @@ -193,7 +193,7 @@ class automount_delkey(crud.Del): :param kw: "key" the key to be removed """ ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) keys = api.Command['automount_getkeys'](mapname) keydn = None keyname = kw.get('automountkey').lower() @@ -235,7 +235,7 @@ class automount_modmap(crud.Mod): assert 'automountmapname' not in kw assert 'dn' not in kw ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) return ldap.update(dn, **kw) def output_for_cli(self, ret): @@ -274,7 +274,7 @@ class automount_modkey(crud.Mod): keyname = kw.get('automountkey').lower() del kw['automountkey'] ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) keys = api.Command['automount_getkeys'](mapname) keydn = None if keys: @@ -388,7 +388,7 @@ class automount_showmap(crud.Get): :param kw: "all" set to True = return all attributes """ ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) # FIXME: should kw contain the list of attributes to display? if kw.get('all', False): return ldap.retrieve(dn) @@ -420,7 +420,7 @@ class automount_showkey(crud.Get): :param kw: "all" set to True = return all attributes """ ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) keys = api.Command['automount_getkeys'](mapname) keyname = kw.get('automountkey').lower() keydn = None @@ -468,7 +468,7 @@ class automount_getkeys(frontend.Command): :param mapname: Retrieve all keys for this mapname """ ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) try: keys = ldap.get_one_entry(dn, 'objectclass=*', ['automountkey']) except errors.NotFound: -- cgit From 9de56d43f054bc5e509e38bda1a048e5af6d73d7 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 14 Nov 2008 21:58:39 -0700 Subject: env plugin now subclasses from RemoteOrLocal --- ipalib/plugins/f_misc.py | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_misc.py b/ipalib/plugins/f_misc.py index 05fd6d52..6988d6f8 100644 --- a/ipalib/plugins/f_misc.py +++ b/ipalib/plugins/f_misc.py @@ -21,44 +21,36 @@ Misc frontend plugins. """ -from ipalib import api, Command, Param, Bool +from ipalib import api, LocalOrRemote # FIXME: We should not let env return anything in_server # when mode == 'production'. This would allow an attacker to see the # configuration of the server, potentially revealing compromising # information. However, it's damn handy for testing/debugging. -class env(Command): +class env(LocalOrRemote): """Show environment variables""" takes_args = ('variables*',) - takes_options = ( - Param('server?', type=Bool(), default=False, - doc='Show environment variables of server', - ), - ) - - def run(self, variables, **options): - if options['server'] and not self.env.in_server: - return self.forward(variables) - return self.execute(variables) - - def find_keys(self, variables): + def __find_keys(self, variables): for key in variables: if key in self.env: yield (key, self.env[key]) - def execute(self, variables): + def execute(self, variables, **options): if variables is None: return tuple( (key, self.env[key]) for key in self.env ) - return tuple(self.find_keys(variables)) + return tuple(self.__find_keys(variables)) def output_for_cli(self, textui, result, variables, **options): if len(result) == 0: return + if len(result) == 1: + textui.print_keyval(result) + return textui.print_name(self.name) textui.print_keyval(result) textui.print_count(result, '%d variable', '%d variables') -- cgit From e059591d6b190cbc6c50d0b96e1f63fddb30a934 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Fri, 14 Nov 2008 22:21:36 -0700 Subject: env command now supports * wildcard for searching --- ipalib/plugins/f_misc.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_misc.py b/ipalib/plugins/f_misc.py index 6988d6f8..b2f97c71 100644 --- a/ipalib/plugins/f_misc.py +++ b/ipalib/plugins/f_misc.py @@ -21,9 +21,11 @@ Misc frontend plugins. """ +import re from ipalib import api, LocalOrRemote + # FIXME: We should not let env return anything in_server # when mode == 'production'. This would allow an attacker to see the # configuration of the server, potentially revealing compromising @@ -34,16 +36,25 @@ class env(LocalOrRemote): takes_args = ('variables*',) def __find_keys(self, variables): - for key in variables: - if key in self.env: - yield (key, self.env[key]) + keys = set() + for query in variables: + if '*' in query: + pat = re.compile(query.replace('*', '.*') + '$') + for key in self.env: + if pat.match(key): + keys.add(key) + elif query in self.env: + keys.add(query) + return sorted(keys) def execute(self, variables, **options): if variables is None: - return tuple( - (key, self.env[key]) for key in self.env - ) - return tuple(self.__find_keys(variables)) + keys = self.env + else: + keys = self.__find_keys(variables) + return tuple( + (key, self.env[key]) for key in keys + ) def output_for_cli(self, textui, result, variables, **options): if len(result) == 0: @@ -53,6 +64,6 @@ class env(LocalOrRemote): return textui.print_name(self.name) textui.print_keyval(result) - textui.print_count(result, '%d variable', '%d variables') + textui.print_count(result, '%d variables') api.register(env) -- cgit From e7ec4131589d5d387c4257bca76e91a17ad7e1a3 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Sun, 16 Nov 2008 19:50:17 -0700 Subject: Moved plugins command from ipalib.cli to ipalib.plugins.f_misc --- ipalib/plugins/f_misc.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_misc.py b/ipalib/plugins/f_misc.py index b2f97c71..a2f0fa4e 100644 --- a/ipalib/plugins/f_misc.py +++ b/ipalib/plugins/f_misc.py @@ -67,3 +67,23 @@ class env(LocalOrRemote): textui.print_count(result, '%d variables') api.register(env) + + +class plugins(LocalOrRemote): + """Show all loaded plugins""" + + def execute(self, **options): + plugins = sorted(self.api.plugins, key=lambda o: o.plugin) + return tuple( + (p.plugin, p.bases) for p in plugins + ) + + def output_for_cli(self, textui, result, **options): + textui.print_name(self.name) + for (plugin, bases) in result: + textui.print_indented( + '%s: %s' % (plugin, ', '.join(bases)) + ) + textui.print_count(result, '%d plugin loaded', '%s plugins loaded') + +api.register(plugins) -- cgit From 42bf555a3ad1f1777b26a4092b49512b9360c882 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 17 Nov 2008 15:27:08 -0700 Subject: Started updated user_* commands to use textui --- ipalib/plugins/f_user.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 3adb328c..e96d787b 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -191,18 +191,21 @@ class user_add(crud.Add): kw['objectClass'] = config.get('ipauserobjectclasses') return ldap.create(**kw) - def output_for_cli(self, ret): + + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "User added" + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Added user "%s"' % result['uid']) api.register(user_add) class user_del(crud.Del): 'Delete an existing user.' + def execute(self, uid, **kw): """Delete a user. Not to be confused with inactivate_user. This makes the entry go away completely. @@ -224,12 +227,12 @@ class user_del(crud.Del): ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("uid", uid) return ldap.delete(dn) - def output_for_cli(self, ret): + + def output_for_cli(self, textui, result, uid): """ Output result of this command to command line interface. """ - if ret: - print "User deleted" + textui.print_plain('Deleted user "%s"' % uid) api.register(user_del) @@ -254,12 +257,13 @@ class user_mod(crud.Mod): dn = ldap.find_entry_dn("uid", uid) return ldap.update(dn, **kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, uid, **options): """ Output result of this command to command line interface. """ - if ret: - print "User updated" + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Updated user "%s"' % result['uid']) api.register(user_mod) @@ -330,9 +334,10 @@ class user_show(crud.Get): return ldap.retrieve(dn) else: return ldap.retrieve(dn, default_attributes) - def output_for_cli(self, user): - if user: - display_user(user) + + def output_for_cli(self, textui, result, uid, **options): + if result: + display_user(result) api.register(user_show) -- cgit From 12dc0a0aa916c9289fe7fb36eddf887e3a53775e Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 17 Nov 2008 16:40:42 -0700 Subject: user-find now works again, uses textui --- ipalib/plugins/f_user.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index e96d787b..eed6d8ab 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -292,21 +292,26 @@ class user_find(crud.Find): else: kw['attributes'] = default_attributes return ldap.search(**kw) - def output_for_cli(self, users): - if not users: + + def output_for_cli(self, textui, result, uid, **options): + counter = result[0] + users = result[1:] + if counter == 0 or len(users) == 0: + textui.print_plain("No entries found") return - counter = users[0] - users = users[1:] - if counter == 0: - print "No entries found" + if len(users) == 1: + textui.print_entry(users[0]) return - elif counter == -1: - print "These results are truncated." - print "Please refine your search and try again." - + textui.print_name(self.name) for u in users: - display_user(u) - print "" + textui.print_plain('%(givenname)s %(sn)s:' % u) + textui.print_entry(u) + textui.print_plain('') + if counter == -1: + textui.print_plain('These results are truncated.') + textui.print_plain('Please refine your search and try again.') + textui.print_count(users, '%d users matched') + api.register(user_find) -- cgit From 5c16047092652d2d56c86d83259c56eff883b485 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 17 Nov 2008 18:15:40 -0700 Subject: user-lock and user-unlock commands now use textui, which finishes the user plugins --- ipalib/plugins/f_user.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index eed6d8ab..ad7572c2 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -348,28 +348,37 @@ api.register(user_show) class user_lock(frontend.Command): 'Lock a user account.' + takes_args = ( Param('uid', primary_key=True), ) + def execute(self, uid, **kw): ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("uid", uid) return ldap.mark_entry_inactive(dn) - def output_for_cli(self, ret): - if ret: - print "User locked" + + def output_for_cli(self, textui, result, uid): + if result: + textui.print_plain('Locked user "%s"' % uid) + api.register(user_lock) + class user_unlock(frontend.Command): 'Unlock a user account.' + takes_args = ( Param('uid', primary_key=True), ) + def execute(self, uid, **kw): ldap = self.api.Backend.ldap dn = ldap.find_entry_dn("uid", uid) return ldap.mark_entry_active(dn) - def output_for_cli(self, ret): - if ret: - print "User unlocked" + + def output_for_cli(self, textui, result, uid): + if result: + textui.print_plain('Unlocked user "%s"' % uid) + api.register(user_unlock) -- cgit From 0a60a6bcc4c8eaa7d42dc25fa6fc69d837e3e816 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 18 Nov 2008 11:30:16 -0700 Subject: Added textui.prompt_password() method; added logic in cli for dealing with 'password' flag in param.flags --- ipalib/plugins/f_user.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index ad7572c2..e1076242 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -109,7 +109,8 @@ class user(frontend.Object): ), Param('userpassword?', cli_name='password', - doc='User\'s password', + doc="Set user's password", + flags=['password'], ), Param('groups?', doc='Add account to one or more groups (comma-separated)', -- cgit From 4afee15d4b523a641552bee9993882bb1ae6e2cc Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Tue, 18 Nov 2008 13:43:43 -0700 Subject: Calling 'passwd' command now prompts for password using textui.prompt_password() --- ipalib/plugins/f_passwd.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py index 7b424a3b..edc13b63 100644 --- a/ipalib/plugins/f_passwd.py +++ b/ipalib/plugins/f_passwd.py @@ -30,14 +30,17 @@ from ipalib import util class passwd(frontend.Command): 'Edit existing password policy.' + takes_args = ( Param('principal', cli_name='user', primary_key=True, default_from=util.get_current_principal, ), + Param('password', flags=['password']), ) - def execute(self, principal, **kw): + + def execute(self, principal, password): """ Execute the passwd operation. @@ -49,8 +52,6 @@ class passwd(frontend.Command): :param param uid: The login name of the user being updated. :param kw: Not used. """ - ldap = self.api.Backend.ldap - if principal.find('@') < 0: u = principal.split('@') if len(u) > 2 or len(u) == 0: @@ -59,16 +60,15 @@ class passwd(frontend.Command): principal = principal+"@"+self.api.env.realm else: principal = principal + dn = self.Backend.ldap.find_entry_dn( + "krbprincipalname", + principal, + "posixAccount" + ) + return self.Backend.ldap.modify_password(dn, newpass=password) - dn = ldap.find_entry_dn("krbprincipalname", principal, "posixAccount") - - # FIXME: we need a way to prompt for passwords using getpass - kw['newpass'] = "password" - - return ldap.modify_password(dn, **kw) - - def output_for_cli(self, ret): - if ret: - print "Password change successful" + def output_for_cli(self, textui, result, principal, password): + assert password is None + textui.print_plain('Changed password for "%s"' % principal) api.register(passwd) -- cgit From 2db738e8996528502293b8cc6861efedcba22c9a Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 24 Nov 2008 10:09:30 -0700 Subject: Some changes to make reading dubugging output easier --- ipalib/plugins/b_xmlrpc.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index 22361b1b..b6e113a5 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -51,14 +51,15 @@ class xmlrpc(Backend): if uri.startswith('https://'): return xmlrpclib.ServerProxy(uri, transport=KerbTransport(), - verbose=self.api.env.verbose, + #verbose=self.api.env.verbose, ) - return xmlrpclib.ServerProxy(uri, verbose=self.api.env.verbose) + return xmlrpclib.ServerProxy(uri) def forward_call(self, name, *args, **kw): """ Forward a call over XML-RPC to an IPA server. """ + self.info('Forwarding %r call to %r' % (name, self.env.xmlrpc_uri)) client = self.get_client() command = getattr(client, name) params = xmlrpc_marshal(*args, **kw) -- cgit From 237c16f0fd3998f4a2e69d9096997d10af2cf8c9 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Mon, 24 Nov 2008 12:51:03 -0700 Subject: Started moving xmlrpc-functions from ipalib.util to ipalib.rpc --- ipalib/plugins/b_xmlrpc.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/b_xmlrpc.py b/ipalib/plugins/b_xmlrpc.py index b6e113a5..14f2a9be 100644 --- a/ipalib/plugins/b_xmlrpc.py +++ b/ipalib/plugins/b_xmlrpc.py @@ -47,11 +47,10 @@ class xmlrpc(Backend): # Are there any reasonably common XML-RPC client implementations # that don't support the extension? # See: http://docs.python.org/library/xmlrpclib.html - uri = self.api.env.xmlrpc_uri + uri = self.env.xmlrpc_uri if uri.startswith('https://'): return xmlrpclib.ServerProxy(uri, transport=KerbTransport(), - #verbose=self.api.env.verbose, ) return xmlrpclib.ServerProxy(uri) -- cgit From fc8ac693726ec33b5c0924f9b8ff5d663705a5a3 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 5 Dec 2008 15:31:18 -0500 Subject: Port plugins to use the new output_for_cli() argument list Fix some errors uncovered by the nosetests --- ipalib/plugins/f_automount.py | 95 ++++++++++++++++++++----------------------- ipalib/plugins/f_group.py | 95 +++++++++++++++++++++++++++---------------- ipalib/plugins/f_hostgroup.py | 21 ++++++++-- ipalib/plugins/f_user.py | 4 +- 4 files changed, 126 insertions(+), 89 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py index 7a251572..d2a70784 100644 --- a/ipalib/plugins/f_automount.py +++ b/ipalib/plugins/f_automount.py @@ -34,14 +34,14 @@ from ldap import explode_dn map_attributes = ['automountMapName', 'description', ] key_attributes = ['description', 'automountKey', 'automountInformation'] -def display_entry(entry): +def display_entry(textui, entry): # FIXME: for now delete dn here. In the future pass in the kw to # output_for_cli() attr = sorted(entry.keys()) for a in attr: if a != 'dn': - print "%s: %s" % (a, entry[a]) + textui.print_plain("%s: %s" % (a, entry[a])) def make_automount_dn(mapname): """ @@ -96,12 +96,11 @@ class automount_addmap(crud.Add): kw['objectClass'] = ['automountMap'] return ldap.create(**kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, map, **options): """ Output result of this command to command line interface. """ - if ret: - print "Automount map added" + textui.print_plain("Automount map %s added" % map) api.register(automount_addmap) @@ -139,12 +138,11 @@ class automount_addkey(crud.Add): kw['objectClass'] = ['automount'] return ldap.create(**kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Automount key added" + textui.print_plain("Automount key added") api.register(automount_addkey) @@ -161,18 +159,17 @@ class automount_delmap(crud.Del): :param kw: Not used. """ ldap = self.api.Backend.ldap - dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap") + dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) keys = api.Command['automount_getkeys'](mapname) if keys: for k in keys: ldap.delete(k.get('dn')) return ldap.delete(dn) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Automount map and associated keys deleted" + print "Automount map and associated keys deleted" api.register(automount_delmap) @@ -205,12 +202,11 @@ class automount_delkey(crud.Del): if not keydn: raise errors.NotFound return ldap.delete(keydn) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Automount key deleted" + print "Automount key deleted" api.register(automount_delkey) @@ -238,12 +234,11 @@ class automount_modmap(crud.Mod): dn = ldap.find_entry_dn("automountmapname", mapname, "automountmap", api.env.container_automount) return ldap.update(dn, **kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Automount map updated" + print "Automount map updated" api.register(automount_modmap) @@ -286,12 +281,12 @@ class automount_modkey(crud.Mod): raise errors.NotFound return ldap.update(keydn, **kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Automount key updated" + print "Automount key updated" + api.register(automount_modkey) @@ -309,26 +304,27 @@ class automount_findmap(crud.Find): kw[s] = term kw['objectclass'] = 'automountMap' + kw['base'] = api.env.container_automount if kw.get('all', False): kw['attributes'] = ['*'] else: kw['attributes'] = map_attributes return ldap.search(**kw) - def output_for_cli(self, entries): - if not entries: - return - counter = entries[0] - entries = entries[1:] + + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + entries = result[1:] if counter == 0: - print "No entries found" + textui.print_plain("No entries found") return elif counter == -1: - print "These results are truncated." - print "Please refine your search and try again." + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") for e in entries: - display_entry(e) - print "" + display_entry(textui, e) + textui.print_plain("") + api.register(automount_findmap) @@ -350,26 +346,26 @@ class automount_findkey(crud.Find): kw[s] = term kw['objectclass'] = 'automount' + kw['base'] = api.env.container_automount if kw.get('all', False): kw['attributes'] = ['*'] else: kw['attributes'] = key_attributes return ldap.search(**kw) - def output_for_cli(self, entries): - if not entries: - return - counter = entries[0] - entries = entries[1:] + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + entries = result[1:] if counter == 0: - print "No entries found" + textui.print_plain("No entries found") return elif counter == -1: - print "These results are truncated." - print "Please refine your search and try again." + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") for e in entries: - display_entry(e) - print "" + display_entry(textui, e) + textui.print_plain("") + api.register(automount_findkey) @@ -394,9 +390,9 @@ class automount_showmap(crud.Get): return ldap.retrieve(dn) else: return ldap.retrieve(dn, map_attributes) - def output_for_cli(self, entry): - if entry: - display_entry(entry) + def output_for_cli(self, textui, result, *args, **options): + if result: + display_entry(textui, result) api.register(automount_showmap) @@ -436,7 +432,7 @@ class automount_showkey(crud.Get): return ldap.retrieve(keydn) else: return ldap.retrieve(keydn, key_attributes) - def output_for_cli(self, entry): + def output_for_cli(self, textui, result, *args, **options): # The automount map name associated with this key is available only # in the dn. Add it as an attribute to display instead. if entry and not entry.get('automountmapname'): @@ -445,7 +441,7 @@ class automount_showkey(crud.Get): (attr, value) = e.split('=',1) if attr == 'automountmapname': entry['automountmapname'] = value - display_entry(entry) + display_entry(textui, entry) api.register(automount_showkey) @@ -475,9 +471,8 @@ class automount_getkeys(frontend.Command): keys = [] return keys - def output_for_cli(self, keys): - if keys: - for k in keys: - print k.get('automountkey') + def output_for_cli(self, textui, result, *args, **options): + for k in result: + textui.print_plain('%s' % k.get('automountkey')) api.register(automount_getkeys) diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index 9df83a29..6fe95006 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -29,6 +29,19 @@ from ipalib import errors from ipalib import ipa_types +def get_members(members): + """ + Return a list of members. + + It is possible that the value passed in is None. + """ + if members: + members = members.split(',') + else: + members = [] + + return members + class group(frontend.Object): """ Group object. @@ -83,12 +96,13 @@ class group_add(crud.Add): return ldap.create(**kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Group added" + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Added group "%s"' % result['cn']) api.register(group_add) @@ -121,12 +135,11 @@ class group_del(crud.Del): return ldap.delete(dn) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, cn): """ Output result of this command to command line interface. """ - if ret: - print "Group deleted" + textui.print_plain("Deleted group %s" % cn) api.register(group_del) @@ -151,12 +164,12 @@ class group_mod(crud.Mod): dn = ldap.find_entry_dn("cn", cn, "posixGroup") return ldap.update(dn, **kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, cn, **options): """ Output result of this command to command line interface. """ - if ret: - print "Group updated" + if result: + textui.print_plain("Group updated") api.register(group_mod) @@ -179,22 +192,24 @@ class group_find(crud.Find): kw['objectclass'] = object_type return ldap.search(**kw) - def output_for_cli(self, groups): - if not groups: + def output_for_cli(self, textui, result, uid, **options): + counter = result[0] + groups = result[1:] + if counter == 0 or len(groups) == 0: + textui.print_plain("No entries found") return - - counter = groups[0] - groups = groups[1:] - if counter == 0: - print "No entries found" + if len(groups) == 1: + textui.print_entry(groups[0]) return - elif counter == -1: - print "These results are truncated." - print "Please refine your search and try again." + textui.print_name(self.name) for g in groups: - for a in g.keys(): - print "%s: %s" % (a, g[a]) + textui.print_entry(g) + textui.print_plain('') + if counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") + textui.print_count(groups, '%d groups matched') api.register(group_find) @@ -218,12 +233,24 @@ class group_show(crud.Get): # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) - def output_for_cli(self, group): - if not group: + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + groups = result[1:] + if counter == 0 or len(groups) == 0: + textui.print_plain("No entries found") return - - for a in group.keys(): - print "%s: %s" % (a, group[a]) + if len(groups) == 1: + textui.print_entry(groups[0]) + return + textui.print_name(self.name) + for u in groups: + textui.print_plain('%(givenname)s %(sn)s:' % u) + textui.print_entry(u) + textui.print_plain('') + if counter == -1: + textui.print_plain('These results are truncated.') + textui.print_plain('Please refine your search and try again.') + textui.print_count(groups, '%d groups matched') api.register(group_show) @@ -253,7 +280,7 @@ class group_add_member(frontend.Command): to_add = [] completed = 0 - members = kw.get('groups', '').split(',') + members = get_members(kw.get('groups', '')) for m in members: if not m: continue try: @@ -263,7 +290,7 @@ class group_add_member(frontend.Command): add_failed.append(m) continue - members = kw.get('users', '').split(',') + members = get_members(kw.get('users', '')) for m in members: if not m: continue try: @@ -282,11 +309,11 @@ class group_add_member(frontend.Command): return add_failed - def output_for_cli(self, add_failed): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if add_failed: + if result: print "These entries failed to add to the group:" for a in add_failed: print "\t'%s'" % a @@ -320,7 +347,7 @@ class group_remove_member(frontend.Command): remove_failed = [] completed = 0 - members = kw.get('groups', '').split(',') + members = get_members(kw.get('groups', '')) for m in members: if not m: continue try: @@ -330,7 +357,7 @@ class group_remove_member(frontend.Command): remove_failed.append(m) continue - members = kw.get('users', '').split(',') + members = get_members(kw.get('users', '')) for m in members: try: member_dn = ldap.find_entry_dn("uid", m,) @@ -348,11 +375,11 @@ class group_remove_member(frontend.Command): return remove_failed - def output_for_cli(self, remove_failed): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if remove_failed: + if result: print "These entries failed to be removed from the group:" for a in remove_failed: print "\t'%s'" % a diff --git a/ipalib/plugins/f_hostgroup.py b/ipalib/plugins/f_hostgroup.py index 8e4c3740..6cbf4d51 100644 --- a/ipalib/plugins/f_hostgroup.py +++ b/ipalib/plugins/f_hostgroup.py @@ -30,6 +30,19 @@ from ipalib import ipa_types hostgroup_filter = "groupofnames)(!(objectclass=posixGroup)" +def get_members(members): + """ + Return a list of members. + + It is possible that the value passed in is None. + """ + if members: + members = members.split(',') + else: + members = [] + + return members + class hostgroup(frontend.Object): """ Host Group object. @@ -241,7 +254,7 @@ class hostgroup_add_member(frontend.Command): to_add = [] completed = 0 - members = kw.get('groups', '').split(',') + members = get_members(kw.get('groups', '')) for m in members: if not m: continue try: @@ -251,7 +264,7 @@ class hostgroup_add_member(frontend.Command): add_failed.append(m) continue - members = kw.get('hosts', '').split(',') + members = get_members(kw.get('hosts', '')) for m in members: if not m: continue try: @@ -309,7 +322,7 @@ class hostgroup_remove_member(frontend.Command): remove_failed = [] completed = 0 - members = kw.get('groups', '').split(',') + members = get_members(kw.get('groups', '')) for m in members: if not m: continue try: @@ -319,7 +332,7 @@ class hostgroup_remove_member(frontend.Command): remove_failed.append(m) continue - members = kw.get('hosts', '').split(',') + members = get_members(kw.get('hosts', '')) for m in members: if not m: continue try: diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index e1076242..c8b819dd 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -305,7 +305,9 @@ class user_find(crud.Find): return textui.print_name(self.name) for u in users: - textui.print_plain('%(givenname)s %(sn)s:' % u) + gn = u.get('givenname', '') + sn= u.get('sn', '') + textui.print_plain('%s %s:' % (gn, sn)) textui.print_entry(u) textui.print_plain('') if counter == -1: -- cgit From 039ee0fd56bbca60a79c99cdd489a1590f6f2b78 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 8 Dec 2008 15:37:36 -0500 Subject: Add a function to show all the maps under a given mapname, def. is auto.master --- ipalib/plugins/f_automount.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py index d2a70784..8de6c5ab 100644 --- a/ipalib/plugins/f_automount.py +++ b/ipalib/plugins/f_automount.py @@ -476,3 +476,35 @@ class automount_getkeys(frontend.Command): textui.print_plain('%s' % k.get('automountkey')) api.register(automount_getkeys) + + +class automount_getmaps(frontend.Command): + 'Retrieve all automount maps' + takes_args = ( + Param('automountmapname?', + cli_name='mapname', + primary_key=True, + doc='A group of related automount objects', + ), + ) + def execute(self, mapname, **kw): + """ + Execute the automount-getmaps operation. + + Return a list of all automount maps. + """ + + ldap = self.api.Backend.ldap + base = api.env.container_automount + "," + api.env.basedn + + if not mapname: + mapname = "auto.master" + search_base = "automountmapname=%s,%s" % (mapname, base) + maps = ldap.get_one_entry(search_base, "objectClass=*", ["*"]) + + return maps + def output_for_cli(self, textui, result, *args, **options): + for k in result: + textui.print_plain('%s: %s' % (k.get('automountinformation'), k.get('automountkey'))) + +api.register(automount_getmaps) -- cgit From c34d2b8923ba0c8dc9a8aa1779a507a64c7c77db Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 10 Dec 2008 13:53:33 -0500 Subject: Add helper for adding Indirect maps. This creates the map and the key pointing to the map. By default the key is associated with the auto.master map but it can be overriden. --- ipalib/plugins/f_automount.py | 57 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 4 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py index 8de6c5ab..4c392438 100644 --- a/ipalib/plugins/f_automount.py +++ b/ipalib/plugins/f_automount.py @@ -435,13 +435,13 @@ class automount_showkey(crud.Get): def output_for_cli(self, textui, result, *args, **options): # The automount map name associated with this key is available only # in the dn. Add it as an attribute to display instead. - if entry and not entry.get('automountmapname'): - elements = explode_dn(entry.get('dn').lower()) + if result and not result.get('automountmapname'): + elements = explode_dn(result.get('dn').lower()) for e in elements: (attr, value) = e.split('=',1) if attr == 'automountmapname': - entry['automountmapname'] = value - display_entry(textui, entry) + result['automountmapname'] = value + display_entry(textui, result) api.register(automount_showkey) @@ -508,3 +508,52 @@ class automount_getmaps(frontend.Command): textui.print_plain('%s: %s' % (k.get('automountinformation'), k.get('automountkey'))) api.register(automount_getmaps) + +class automount_addindirectmap(crud.Add): + 'Add a new automap indirect mount point.' + takes_options = ( + Param('parentmap?', + cli_name='parentmap', + default='auto.master', + doc='The parent map to connect this to. Default: auto.master'), + Param('automountkey', + cli_name='key', + doc='An entry in an automount map'), + Param('description?', + doc='A description of the automount map'), + ) + + def execute(self, mapname, **kw): + """ + Execute the automount-addindirectmap operation. + + Returns the key entry as it will be created in LDAP. + + This function creates 2 LDAP entries. It creates an + automountmapname entry and an automountkey entry. + + :param mapname: The map name being added. + :param kw['parentmap'] is the top-level map to add this to. + defaulting to auto.master + :param kw['automountkey'] is the mount point + :param kw['description'] is a textual description of this map + """ + mapkw = {} + if kw.get('description'): + mapkw['description'] = kw.get('description') + newmap = api.Command['automount_addmap'](mapname, **mapkw) + + keykw = {'automountkey': kw['automountkey'], 'automountinformation': mapname} + if kw.get('description'): + keykw['description'] = kw.get('description') + newkey = api.Command['automount_addkey'](kw['parentmap'], **keykw) + + return newkey + def output_for_cli(self, textui, result, map, **options): + """ + Output result of this command to command line interface. + """ + textui.print_plain("Indirect automount map %s added" % map) + +api.register(automount_addindirectmap) + -- cgit From af7b5645af001352aff626f46ec39031b2e9b10a Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 10 Dec 2008 16:42:45 -0500 Subject: Convert to new output_for_cli() function --- ipalib/plugins/f_host.py | 40 +++++++++++---------------- ipalib/plugins/f_hostgroup.py | 64 ++++++++++++++++++------------------------- ipalib/plugins/f_pwpolicy.py | 21 ++++++-------- ipalib/plugins/f_service.py | 30 ++++++++------------ 4 files changed, 64 insertions(+), 91 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py index e842230f..020231e5 100644 --- a/ipalib/plugins/f_host.py +++ b/ipalib/plugins/f_host.py @@ -149,12 +149,11 @@ class host_add(crud.Add): kw['objectclass'].remove('krbprincipalaux') return ldap.create(**kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Host added" + textui.print_plain("Host added") api.register(host_add) @@ -172,12 +171,11 @@ class host_del(crud.Del): ldap = self.api.Backend.ldap dn = get_host(hostname) return ldap.delete(dn) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Host deleted" + textui.print_plain("Host deleted") api.register(host_del) @@ -202,12 +200,11 @@ class host_mod(crud.Mod): dn = get_host(hostname) return ldap.update(dn, **kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Host updated" + textui.print_plain("Host updated") api.register(host_mod) @@ -242,21 +239,18 @@ class host_find(crud.Find): else: kw['attributes'] = default_attributes return ldap.search(**kw) - def output_for_cli(self, hosts): - if not hosts: - return - counter = hosts[0] - hosts = hosts[1:] + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + hosts = result[1:] if counter == 0: - print "No entries found" + textui.print_plain("No entries found") return - elif counter == -1: - print "These results are truncated." - print "Please refine your search and try again." for h in hosts: - for a in h.keys(): - print "%s: %s" % (a, h[a]) + textui.print_entry(h) + if counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") api.register(host_find) @@ -286,9 +280,7 @@ class host_show(crud.Get): value = ldap.retrieve(dn, default_attributes) del value['dn'] return value - def output_for_cli(self, host): - if host: - for a in host.keys(): - print "%s: %s" % (a, host[a]) + def output_for_cli(self, textui, result, *args, **options): + textui.print_entry(result) api.register(host_show) diff --git a/ipalib/plugins/f_hostgroup.py b/ipalib/plugins/f_hostgroup.py index 6cbf4d51..bde257f9 100644 --- a/ipalib/plugins/f_hostgroup.py +++ b/ipalib/plugins/f_hostgroup.py @@ -93,12 +93,11 @@ class hostgroup_add(crud.Add): return ldap.create(**kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Group added" + textui.print_plain("Group added") api.register(hostgroup_add) @@ -120,12 +119,11 @@ class hostgroup_del(crud.Del): return ldap.delete(dn) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Group deleted" + textui.print_plain("Group deleted") api.register(hostgroup_del) @@ -150,12 +148,11 @@ class hostgroup_mod(crud.Mod): dn = ldap.find_entry_dn("cn", cn, hostgroup_filter) return ldap.update(dn, **kw) - def output_for_cli(self, ret): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if ret: - print "Group updated" + texui.print_plain("Group updated") api.register(hostgroup_mod) @@ -178,22 +175,19 @@ class hostgroup_find(crud.Find): kw['objectclass'] = hostgroup_filter return ldap.search(**kw) - def output_for_cli(self, groups): - if not groups: - return - - counter = groups[0] - groups = groups[1:] + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + groups = result[1:] if counter == 0: - print "No entries found" + textui.print_plain("No entries found") return - elif counter == -1: - print "These results are truncated." - print "Please refine your search and try again." for g in groups: - for a in g.keys(): - print "%s: %s" % (a, g[a]) + textui.print_entry(g) + + if counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") api.register(hostgroup_find) @@ -219,12 +213,8 @@ class hostgroup_show(crud.Get): # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) - def output_for_cli(self, group): - if not group: - return - - for a in group.keys(): - print "%s: %s" % (a, group[a]) + def output_for_cli(self, textui, result, *args, **options): + textui.print_entry(result) api.register(hostgroup_show) @@ -283,16 +273,16 @@ class hostgroup_add_member(frontend.Command): return add_failed - def output_for_cli(self, add_failed): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if add_failed: - print "These entries failed to add to the group:" - for a in add_failed: + if result: + textui.print_plain("These entries failed to add to the group:") + for a in result: print "\t'%s'" % a else: - print "Group membership updated." + textui.print_entry("Group membership updated.") api.register(hostgroup_add_member) @@ -351,15 +341,15 @@ class hostgroup_remove_member(frontend.Command): return remove_failed - def output_for_cli(self, remove_failed): + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. """ - if remove_failed: - print "These entries failed to be removed from the group:" - for a in remove_failed: + if result: + textui.print_plain("These entries failed to be removed from the group:") + for a in result: print "\t'%s'" % a else: - print "Group membership updated." + textui.print_plain("Group membership updated.") api.register(hostgroup_remove_member) diff --git a/ipalib/plugins/f_pwpolicy.py b/ipalib/plugins/f_pwpolicy.py index ce52e467..87a7d8fa 100644 --- a/ipalib/plugins/f_pwpolicy.py +++ b/ipalib/plugins/f_pwpolicy.py @@ -88,9 +88,8 @@ class pwpolicy_mod(frontend.Command): return ldap.update(dn, **kw) - def output_for_cli(self, ret): - if ret: - print "Policy modified" + def output_for_cli(self, textui, result, *args, **options): + textui.print_plain("Policy modified") api.register(pwpolicy_mod) @@ -120,14 +119,12 @@ class pwpolicy_show(frontend.Command): return policy - def output_for_cli(self, policy): - if not policy: return - - print "Password Policy" - print "Min. Password Lifetime (hours): %s" % policy.get('krbminpwdlife') - print "Max. Password Lifetime (days): %s" % policy.get('krbmaxpwdlife') - print "Min. Number of Character Classes: %s" % policy.get('krbpwdmindiffchars') - print "Min. Length of Password: %s" % policy.get('krbpwdminlength') - print "Password History Size: %s" % policy.get('krbpwdhistorylength') + def output_for_cli(self, textui, result, *args, **options): + textui.print_plain("Password Policy") + textui.print_plain("Min. Password Lifetime (hours): %s" % result.get('krbminpwdlife')) + textui.print_plain("Max. Password Lifetime (days): %s" % result.get('krbmaxpwdlife')) + textui.print_plain("Min. Number of Character Classes: %s" % result.get('krbpwdmindiffchars')) + textui.print_plain("Min. Length of Password: %s" % result.get('krbpwdminlength')) + textui.print_plain("Password History Size: %s" % result.get('krbpwdhistorylength')) api.register(pwpolicy_show) diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index 04187a86..fc0ae65e 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -158,22 +158,20 @@ class service_find(crud.Find): return ldap.search(**kw) - def output_for_cli(self, services): - if not services: - return - - counter = services[0] - services = services[1:] + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + services = result[1:] if counter == 0: - print "No entries found" + textui.print_plain("No entries found") return - elif counter == -1: - print "These results are truncated." - print "Please refine your search and try again." for s in services: - for a in s.keys(): - print "%s: %s" % (a, s[a]) + textui.print_entry(s) + + if counter == -1: + textui.print_plain("These results are truncated.") + textui.print_plain("Please refine your search and try again.") + textui.print_count(services, '%d services matched') api.register(service_find) @@ -196,11 +194,7 @@ class service_show(crud.Get): dn = ldap.find_entry_dn("krbprincipalname", principal) # FIXME: should kw contain the list of attributes to display? return ldap.retrieve(dn) - def output_for_cli(self, service): - if not service: - return - - for a in service.keys(): - print "%s: %s" % (a, service[a]) + def output_for_cli(self, textui, result, *args, **options): + textui.print_entry(result) api.register(service_show) -- cgit From 46bd3974af5ce312cb1dd3ca12e6184d78dc470e Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 10 Dec 2008 16:45:07 -0500 Subject: Don't pass along the kw dictionary we were passed by XML-RPC. We generally want to just search indexed attributes. We get this list of attributes from the configuration, use it. --- ipalib/plugins/f_group.py | 7 ++++--- ipalib/plugins/f_host.py | 11 ++++++----- ipalib/plugins/f_hostgroup.py | 7 ++++--- ipalib/plugins/f_service.py | 9 +++++---- ipalib/plugins/f_user.py | 11 ++++++----- 5 files changed, 25 insertions(+), 20 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index 6fe95006..803e5d00 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -184,13 +184,14 @@ class group_find(crud.Find): search_fields_conf_str = config.get('ipagroupsearchfields') search_fields = search_fields_conf_str.split(",") + search_kw = {} for s in search_fields: - kw[s] = term + search_kw[s] = term object_type = ldap.get_object_type("cn") if object_type and not kw.get('objectclass'): - kw['objectclass'] = object_type - return ldap.search(**kw) + search_kw['objectclass'] = object_type + return ldap.search(**search_kw) def output_for_cli(self, textui, result, uid, **options): counter = result[0] diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py index 020231e5..7903ff90 100644 --- a/ipalib/plugins/f_host.py +++ b/ipalib/plugins/f_host.py @@ -229,16 +229,17 @@ class host_find(crud.Find): #search_fields = search_fields_conf_str.split(",") search_fields = ['cn','serverhostname','description','localityname','nshostlocation','nshardwareplatform','nsosversion'] + search_kw = {} for s in search_fields: - kw[s] = term + search_kw[s] = term # Can't use ldap.get_object_type() since cn is also used for group dns - kw['objectclass'] = "ipaHost" + search_kw['objectclass'] = "ipaHost" if kw.get('all', False): - kw['attributes'] = ['*'] + search_kw['attributes'] = ['*'] else: - kw['attributes'] = default_attributes - return ldap.search(**kw) + search_kw['attributes'] = default_attributes + return ldap.search(**search_kw) def output_for_cli(self, textui, result, *args, **options): counter = result[0] hosts = result[1:] diff --git a/ipalib/plugins/f_hostgroup.py b/ipalib/plugins/f_hostgroup.py index bde257f9..3e14b09a 100644 --- a/ipalib/plugins/f_hostgroup.py +++ b/ipalib/plugins/f_hostgroup.py @@ -169,11 +169,12 @@ class hostgroup_find(crud.Find): search_fields_conf_str = config.get('ipagroupsearchfields') search_fields = search_fields_conf_str.split(",") + search_kw = {} for s in search_fields: - kw[s] = term + search_kw[s] = term - kw['objectclass'] = hostgroup_filter - return ldap.search(**kw) + search_kw['objectclass'] = hostgroup_filter + return ldap.search(**search_kw) def output_for_cli(self, textui, result, *args, **options): counter = result[0] diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index fc0ae65e..a353d52e 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -149,14 +149,15 @@ class service_find(crud.Find): def execute(self, principal, **kw): ldap = self.api.Backend.ldap - kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=posixAccount))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" - kw['krbprincipalname'] = principal + search_kw = {} + search_kw['filter'] = "&(objectclass=krbPrincipalAux)(!(objectClass=posixAccount))(!(|(krbprincipalname=kadmin/*)(krbprincipalname=K/M@*)(krbprincipalname=krbtgt/*)))" + search_kw['krbprincipalname'] = principal object_type = ldap.get_object_type("krbprincipalname") if object_type and not kw.get('objectclass'): - kw['objectclass'] = object_type + search_kw['objectclass'] = object_type - return ldap.search(**kw) + return ldap.search(**search_kw) def output_for_cli(self, textui, result, *args, **options): counter = result[0] diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index c8b819dd..8cd3a592 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -282,17 +282,18 @@ class user_find(crud.Find): search_fields_conf_str = config.get('ipausersearchfields') search_fields = search_fields_conf_str.split(",") + search_kw = {} for s in search_fields: - kw[s] = term + search_kw[s] = term object_type = ldap.get_object_type("uid") if object_type and not kw.get('objectclass'): - kw['objectclass'] = object_type + search_kw['objectclass'] = object_type if kw.get('all', False): - kw['attributes'] = ['*'] + search_kw['attributes'] = ['*'] else: - kw['attributes'] = default_attributes - return ldap.search(**kw) + search_kw['attributes'] = default_attributes + return ldap.search(**search_kw) def output_for_cli(self, textui, result, uid, **options): counter = result[0] -- cgit From e41fcf19fe82c41fe024b261d94814e092e6abaf Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 11 Dec 2008 10:31:27 -0500 Subject: Raise an error on bad principals instead of printing one when changing passwords Fix logic in determining what to do with an incoming principal --- ipalib/plugins/f_passwd.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py index edc13b63..c82cd455 100644 --- a/ipalib/plugins/f_passwd.py +++ b/ipalib/plugins/f_passwd.py @@ -52,14 +52,14 @@ class passwd(frontend.Command): :param param uid: The login name of the user being updated. :param kw: Not used. """ - if principal.find('@') < 0: + import pdb + pdb.set_trace() + if principal.find('@') > 0: u = principal.split('@') - if len(u) > 2 or len(u) == 0: - print "Invalid user name (%s)" % principal - if len(u) == 1: - principal = principal+"@"+self.api.env.realm - else: - principal = principal + if len(u) > 2: + raise errors.InvalidUserPrincipal, principal + else: + principal = principal+"@"+self.api.env.realm dn = self.Backend.ldap.find_entry_dn( "krbprincipalname", principal, -- cgit From c025ed6404e147f19b71b398e920fd1b3a05452a Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Thu, 11 Dec 2008 16:06:26 -0500 Subject: Remove some debugging statements --- ipalib/plugins/f_passwd.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py index c82cd455..1e0dfc1c 100644 --- a/ipalib/plugins/f_passwd.py +++ b/ipalib/plugins/f_passwd.py @@ -52,8 +52,6 @@ class passwd(frontend.Command): :param param uid: The login name of the user being updated. :param kw: Not used. """ - import pdb - pdb.set_trace() if principal.find('@') > 0: u = principal.split('@') if len(u) > 2: -- cgit From 285fa3d33077b336784a8ea7633b0e011646adaa Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 17 Dec 2008 23:18:14 -0700 Subject: Removed depreciated envtest command from f_user.py --- ipalib/plugins/f_user.py | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index e1076242..45ee59f4 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -28,24 +28,6 @@ from ipalib import api from ipalib import errors from ipalib import ipa_types -# Command to get the idea how plugins will interact with api.env -class envtest(frontend.Command): - 'Show current environment.' - def run(self, *args, **kw): - print "" - print "Environment variables:" - for var in api.env: - val = api.env[var] - if var is 'server': - print "" - print " Servers:" - for item in api.env.server: - print " %s" % item - print "" - else: - print " %s: %s" % (var, val) - return {} -api.register(envtest) def display_user(user): # FIXME: for now delete dn here. In the future pass in the kw to -- cgit From b3f95b17417342c7ede2e4b21cc917d84f8e2b8c Mon Sep 17 00:00:00 2001 From: Andrew Wnuk Date: Sun, 21 Dec 2008 14:15:53 -0700 Subject: Merged in Andrew's RA plugin --- ipalib/plugins/f_ra.py | 119 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 ipalib/plugins/f_ra.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_ra.py b/ipalib/plugins/f_ra.py new file mode 100644 index 00000000..724cbf5e --- /dev/null +++ b/ipalib/plugins/f_ra.py @@ -0,0 +1,119 @@ +# Authors: +# Andrew Wnuk +# Jason Gerard DeRose +# +# Copyright (C) 2009 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugins for IPA-RA PKI operations. +""" + +from ipalib import api, Command, Param +from ipalib import cli + + +class request_certificate(Command): + """ Submit a certificate request. """ + + takes_args = ['csr'] + + takes_options = [Param('request_type?', default='pkcs10')] + + def execute(self, csr, **options): + return self.Backend.ra.request_certificate(csr, **options) + + def output_for_cli(self, textui, result, *args, **options): + if isinstance(result, dict) and len(result) > 0: + textui.print_entry(result, 0) + else: + textui.print_plain('Failed to submit a certificate request.') + +api.register(request_certificate) + + +class get_certificate(Command): + """ Retrieve an existing certificate. """ + + takes_args = ['serial_number'] + + def execute(self, serial_number, **options): + return self.Backend.ra.get_certificate(serial_number) + + def output_for_cli(self, textui, result, *args, **options): + if isinstance(result, dict) and len(result) > 0: + textui.print_entry(result, 0) + else: + textui.print_plain('Failed to obtain a certificate.') + +api.register(get_certificate) + + +class check_request_status(Command): + """ Check a request status. """ + + takes_args = ['request_id'] + + + def execute(self, request_id, **options): + return self.Backend.ra.check_request_status(request_id) + + def output_for_cli(self, textui, result, *args, **options): + if isinstance(result, dict) and len(result) > 0: + textui.print_entry(result, 0) + else: + textui.print_plain('Failed to retrieve a request status.') + +api.register(check_request_status) + + +class revoke_certificate(Command): + """ Revoke a certificate. """ + + takes_args = ['serial_number'] + + takes_options = [Param('revocation_reason?', default=0)] + + + def execute(self, serial_number, **options): + return self.Backend.ra.revoke_certificate(serial_number, **options) + + def output_for_cli(self, textui, result, *args, **options): + if isinstance(result, dict) and len(result) > 0: + textui.print_entry(result, 0) + else: + textui.print_plain('Failed to revoke a certificate.') + +api.register(revoke_certificate) + + +class take_certificate_off_hold(Command): + """ Take a revoked certificate off hold. """ + + takes_args = ['serial_number'] + + def execute(self, serial_number, **options): + return self.Backend.ra.take_certificate_off_hold(serial_number) + + def output_for_cli(self, textui, result, *args, **options): + if isinstance(result, dict) and len(result) > 0: + textui.print_entry(result, 0) + else: + textui.print_plain('Failed to take a revoked certificate off hold.') + +api.register(take_certificate_off_hold) + + -- cgit From 39068ab7ca4cb2346c3c7079a435fb82ebd29591 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 21:11:14 -0700 Subject: Fixed automount plugins module to where it can at least be imported --- ipalib/plugins/f_automount.py | 76 +++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 36 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_automount.py b/ipalib/plugins/f_automount.py index 4c392438..2365ce22 100644 --- a/ipalib/plugins/f_automount.py +++ b/ipalib/plugins/f_automount.py @@ -23,13 +23,9 @@ Frontend plugins for automount. RFC 2707bis http://www.padl.com/~lukeh/rfc2307bis.txt """ -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param -from ipalib import api -from ipalib import errors -from ipalib import ipa_types from ldap import explode_dn +from ipalib import crud, errors +from ipalib import api, Str, Flag, Object, Command map_attributes = ['automountMapName', 'description', ] key_attributes = ['description', 'automountKey', 'automountInformation'] @@ -57,12 +53,12 @@ def make_automount_dn(mapname): api.env.basedn, ) -class automount(frontend.Object): +class automount(Object): """ Automount object. """ takes_params = ( - Param('automountmapname', + Str('automountmapname', cli_name='mapname', primary_key=True, doc='A group of related automount objects', @@ -73,8 +69,9 @@ api.register(automount) class automount_addmap(crud.Add): 'Add a new automount map.' + takes_options = ( - Param('description?', + Str('description?', doc='A description of the automount map'), ) @@ -96,6 +93,7 @@ class automount_addmap(crud.Add): kw['objectClass'] = ['automountMap'] return ldap.create(**kw) + def output_for_cli(self, textui, result, map, **options): """ Output result of this command to command line interface. @@ -108,13 +106,13 @@ api.register(automount_addmap) class automount_addkey(crud.Add): 'Add a new automount key.' takes_options = ( - Param('automountkey', + Str('automountkey', cli_name='key', doc='An entry in an automount map'), - Param('automountinformation', + Str('automountinformation', cli_name='info', doc='Mount information for this key'), - Param('description?', + Str('description?', doc='A description of the mount'), ) @@ -138,6 +136,7 @@ class automount_addkey(crud.Add): kw['objectClass'] = ['automount'] return ldap.create(**kw) + def output_for_cli(self, textui, result, *args, **options): """ Output result of this command to command line interface. @@ -177,7 +176,7 @@ api.register(automount_delmap) class automount_delkey(crud.Del): 'Delete an automount key.' takes_options = ( - Param('automountkey', + Str('automountkey', cli_name='key', doc='The automount key to remove'), ) @@ -213,7 +212,7 @@ api.register(automount_delkey) class automount_modmap(crud.Mod): 'Edit an existing automount map.' takes_options = ( - Param('description?', + Str('description?', doc='A description of the automount map'), ) def execute(self, mapname, **kw): @@ -246,13 +245,13 @@ api.register(automount_modmap) class automount_modkey(crud.Mod): 'Edit an existing automount key.' takes_options = ( - Param('automountkey', + Str('automountkey', cli_name='key', doc='An entry in an automount map'), - Param('automountinformation?', + Str('automountinformation?', cli_name='info', doc='Mount information for this key'), - Param('description?', + Str('description?', doc='A description of the automount map'), ) def execute(self, mapname, **kw): @@ -293,7 +292,7 @@ api.register(automount_modkey) class automount_findmap(crud.Find): 'Search automount maps.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + Flag('all', doc='Retrieve all attributes'), ) def execute(self, term, **kw): ldap = self.api.Backend.ldap @@ -331,10 +330,10 @@ api.register(automount_findmap) class automount_findkey(crud.Find): 'Search automount keys.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + Flag('all?', doc='Retrieve all attributes'), ) def get_args(self): - return (Param('automountkey', + return (Str('automountkey', cli_name='key', doc='An entry in an automount map'),) def execute(self, term, **kw): @@ -372,7 +371,7 @@ api.register(automount_findkey) class automount_showmap(crud.Get): 'Examine an existing automount map.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + Flag('all?', doc='Retrieve all attributes'), ) def execute(self, mapname, **kw): """ @@ -400,10 +399,10 @@ api.register(automount_showmap) class automount_showkey(crud.Get): 'Examine an existing automount key.' takes_options = ( - Param('automountkey', + Str('automountkey', cli_name='key', doc='The automount key to display'), - Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + Flag('all?', doc='Retrieve all attributes'), ) def execute(self, mapname, **kw): """ @@ -446,10 +445,10 @@ class automount_showkey(crud.Get): api.register(automount_showkey) -class automount_getkeys(frontend.Command): +class automount_getkeys(Command): 'Retrieve all keys for an automount map.' takes_args = ( - Param('automountmapname', + Str('automountmapname', cli_name='mapname', primary_key=True, doc='A group of related automount objects', @@ -478,10 +477,10 @@ class automount_getkeys(frontend.Command): api.register(automount_getkeys) -class automount_getmaps(frontend.Command): +class automount_getmaps(Command): 'Retrieve all automount maps' takes_args = ( - Param('automountmapname?', + Str('automountmapname?', cli_name='mapname', primary_key=True, doc='A group of related automount objects', @@ -510,17 +509,23 @@ class automount_getmaps(frontend.Command): api.register(automount_getmaps) class automount_addindirectmap(crud.Add): - 'Add a new automap indirect mount point.' + """ + Add a new automap indirect mount point. + """ + takes_options = ( - Param('parentmap?', + Str('parentmap?', cli_name='parentmap', - default='auto.master', - doc='The parent map to connect this to. Default: auto.master'), - Param('automountkey', + default=u'auto.master', + doc='The parent map to connect this to.', + ), + Str('automountkey', cli_name='key', - doc='An entry in an automount map'), - Param('description?', - doc='A description of the automount map'), + doc='An entry in an automount map', + ), + Str('description?', + doc='A description of the automount map', + ), ) def execute(self, mapname, **kw): @@ -556,4 +561,3 @@ class automount_addindirectmap(crud.Add): textui.print_plain("Indirect automount map %s added" % map) api.register(automount_addindirectmap) - -- cgit From 29e5a58795da7283eb5976d14f8e5344d4db0e28 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 21:23:20 -0700 Subject: Updated group plugins module to where it can at least be imported --- ipalib/plugins/f_group.py | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index 803e5d00..c9d7b86b 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -21,12 +21,9 @@ Frontend plugins for group (Identity). """ -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param -from ipalib import api -from ipalib import errors -from ipalib import ipa_types +from ipalib import api, crud, errors +from ipalib import Object, Command # Plugin base classes +from ipalib import Str, Int # Parameter types def get_members(members): @@ -42,24 +39,23 @@ def get_members(members): return members -class group(frontend.Object): +class group(Object): """ Group object. """ takes_params = ( - Param('description', + Str('description', doc='A description of this group', ), - Param('gidnumber?', + Int('gidnumber?', cli_name='gid', - type=ipa_types.Int(), doc='The gid to use for this group. If not included one is automatically set.', ), - Param('cn', + Str('cn', cli_name='name', primary_key=True, - normalize=lambda value: value.lower(), - ) + normalizer=lambda value: value.lower(), + ), ) api.register(group) @@ -256,14 +252,14 @@ class group_show(crud.Get): api.register(group_show) -class group_add_member(frontend.Command): +class group_add_member(Command): 'Add a member to a group.' takes_args = ( - Param('group', primary_key=True), + Str('group', primary_key=True), ) takes_options = ( - Param('users?', doc='comma-separated list of users to add'), - Param('groups?', doc='comma-separated list of groups to add'), + Str('users?', doc='comma-separated list of users to add'), + Str('groups?', doc='comma-separated list of groups to add'), ) def execute(self, cn, **kw): """ @@ -323,14 +319,14 @@ class group_add_member(frontend.Command): api.register(group_add_member) -class group_remove_member(frontend.Command): +class group_remove_member(Command): 'Remove a member from a group.' takes_args = ( - Param('group', primary_key=True), + Str('group', primary_key=True), ) takes_options = ( - Param('users?', doc='comma-separated list of users to remove'), - Param('groups?', doc='comma-separated list of groups to remove'), + Str('users?', doc='comma-separated list of users to remove'), + Str('groups?', doc='comma-separated list of groups to remove'), ) def execute(self, cn, **kw): """ -- cgit From ec14fbfbc5f822490ed5266f1b0a8eb110a13a98 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 21:55:04 -0700 Subject: Updated host plugins module to where it can at least be imported --- ipalib/plugins/f_host.py | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py index 7903ff90..bb800b50 100644 --- a/ipalib/plugins/f_host.py +++ b/ipalib/plugins/f_host.py @@ -21,13 +21,9 @@ Frontend plugins for host/machine Identity. """ -from ipalib import frontend -from ipalib import crud -from ipalib import util -from ipalib.frontend import Param -from ipalib import api -from ipalib import errors -from ipalib import ipa_types +from ipalib import api, crud, errors +from ipalib import Object # Plugin base class +from ipalib import Str, Flag # Parameter types def get_host(hostname): @@ -57,37 +53,36 @@ def validate_host(cn): default_attributes = ['cn','description','localityname','nshostlocation','nshardwareplatform','nsosversion'] -class host(frontend.Object): +class host(Object): """ Host object. """ takes_params = ( - Param('cn', + Str('cn', validate_host, cli_name='hostname', primary_key=True, - normalize=lambda value: value.lower(), - rules=(validate_host,) + normalizer=lambda value: value.lower(), ), - Param('description?', + Str('description?', doc='Description of the host', ), - Param('localityname?', + Str('localityname?', cli_name='locality', doc='Locality of this host (Baltimore, MD)', ), - Param('nshostlocation?', + Str('nshostlocation?', cli_name='location', doc='Location of this host (e.g. Lab 2)', ), - Param('nshardwareplatform?', + Str('nshardwareplatform?', cli_name='platform', doc='Hardware platform of this host (e.g. Lenovo T61)', ), - Param('nsosversion?', + Str('nsosversion?', cli_name='os', doc='Operating System and version on this host (e.g. Fedora 9)', ), - Param('userpassword?', + Str('userpassword?', cli_name='password', doc='Set a password to be used in bulk enrollment', ), @@ -212,7 +207,7 @@ api.register(host_mod) class host_find(crud.Find): 'Search the hosts.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Retrieve all attributes'), + Flag('all', doc='Retrieve all attributes'), ) def get_args(self): """ @@ -258,7 +253,7 @@ api.register(host_find) class host_show(crud.Get): 'Examine an existing host.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Display all host attributes'), + Flag('all', doc='Display all host attributes'), ) def execute(self, hostname, **kw): """ -- cgit From 64c072b7b3deb1800c242b365e277591f056093d Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 22:10:09 -0700 Subject: Updated hostgroup plugins module to where it can at least be imported --- ipalib/plugins/f_hostgroup.py | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_hostgroup.py b/ipalib/plugins/f_hostgroup.py index 3e14b09a..c365c918 100644 --- a/ipalib/plugins/f_hostgroup.py +++ b/ipalib/plugins/f_hostgroup.py @@ -21,12 +21,10 @@ Frontend plugins for groups of hosts """ -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param -from ipalib import api -from ipalib import errors -from ipalib import ipa_types +from ipalib import api, crud, errors +from ipalib import Object, Command # Plugin base classes +from ipalib import Str # Parameter types + hostgroup_filter = "groupofnames)(!(objectclass=posixGroup)" @@ -43,18 +41,18 @@ def get_members(members): return members -class hostgroup(frontend.Object): +class hostgroup(Object): """ Host Group object. """ takes_params = ( - Param('description', + Str('description', doc='A description of this group', ), - Param('cn', + Str('cn', cli_name='name', primary_key=True, - normalize=lambda value: value.lower(), + normalizer=lambda value: value.lower(), ) ) api.register(hostgroup) @@ -220,14 +218,14 @@ class hostgroup_show(crud.Get): api.register(hostgroup_show) -class hostgroup_add_member(frontend.Command): +class hostgroup_add_member(Command): 'Add a member to a group.' takes_args = ( - Param('group', primary_key=True), + Str('group', primary_key=True), ) takes_options = ( - Param('groups?', doc='comma-separated list of host groups to add'), - Param('hosts?', doc='comma-separated list of hosts to add'), + Str('groups?', doc='comma-separated list of host groups to add'), + Str('hosts?', doc='comma-separated list of hosts to add'), ) def execute(self, cn, **kw): """ @@ -288,14 +286,14 @@ class hostgroup_add_member(frontend.Command): api.register(hostgroup_add_member) -class hostgroup_remove_member(frontend.Command): +class hostgroup_remove_member(Command): 'Remove a member from a group.' takes_args = ( - Param('group', primary_key=True), + Str('group', primary_key=True), ) takes_options = ( - Param('hosts?', doc='comma-separated list of hosts to add'), - Param('groups?', doc='comma-separated list of groups to remove'), + Str('hosts?', doc='comma-separated list of hosts to add'), + Str('groups?', doc='comma-separated list of groups to remove'), ) def execute(self, cn, **kw): """ -- cgit From ec86208a9007ec9febca620c777b80b20e9c360d Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 22:19:31 -0700 Subject: Updated passwd plugins module to where it can at least be imported --- ipalib/plugins/f_group.py | 2 +- ipalib/plugins/f_passwd.py | 16 +++++++--------- 2 files changed, 8 insertions(+), 10 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_group.py b/ipalib/plugins/f_group.py index c9d7b86b..740b32f8 100644 --- a/ipalib/plugins/f_group.py +++ b/ipalib/plugins/f_group.py @@ -23,7 +23,7 @@ Frontend plugins for group (Identity). from ipalib import api, crud, errors from ipalib import Object, Command # Plugin base classes -from ipalib import Str, Int # Parameter types +from ipalib import Str, Int # Parameter types def get_members(members): diff --git a/ipalib/plugins/f_passwd.py b/ipalib/plugins/f_passwd.py index 1e0dfc1c..ea78c4c1 100644 --- a/ipalib/plugins/f_passwd.py +++ b/ipalib/plugins/f_passwd.py @@ -21,23 +21,21 @@ Frontend plugins for password changes. """ -from ipalib import frontend -from ipalib.frontend import Param -from ipalib import api -from ipalib import errors -from ipalib import ipa_types -from ipalib import util +from ipalib import api, errors, util +from ipalib import Command # Plugin base classes +from ipalib import Str, Password # Parameter types -class passwd(frontend.Command): + +class passwd(Command): 'Edit existing password policy.' takes_args = ( - Param('principal', + Str('principal', cli_name='user', primary_key=True, default_from=util.get_current_principal, ), - Param('password', flags=['password']), + Password('password'), ) def execute(self, principal, password): -- cgit From a41a7f406f5e5192ed7a8c1b05c76de1826f0d7b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 22:25:45 -0700 Subject: Updated pwpolicy plugins module to where it can at least be imported --- ipalib/plugins/f_pwpolicy.py | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_pwpolicy.py b/ipalib/plugins/f_pwpolicy.py index 87a7d8fa..d914ce72 100644 --- a/ipalib/plugins/f_pwpolicy.py +++ b/ipalib/plugins/f_pwpolicy.py @@ -21,40 +21,32 @@ Frontend plugins for password policy. """ -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param from ipalib import api -from ipalib import errors -from ipalib import ipa_types +from ipalib import Command # Plugin base classes +from ipalib import Int # Parameter types -class pwpolicy_mod(frontend.Command): +class pwpolicy_mod(Command): 'Edit existing password policy.' takes_options = ( - Param('krbmaxpwdlife?', + Int('krbmaxpwdlife?', cli_name='maxlife', - type=ipa_types.Int(), doc='Max. Password Lifetime (days)' ), - Param('krbminpwdlife?', + Int('krbminpwdlife?', cli_name='minlife', - type=ipa_types.Int(), doc='Min. Password Lifetime (hours)' ), - Param('krbpwdhistorylength?', + Int('krbpwdhistorylength?', cli_name='history', - type=ipa_types.Int(), doc='Password History Size' ), - Param('krbpwdmindiffchars?', + Int('krbpwdmindiffchars?', cli_name='minclasses', - type=ipa_types.Int(), doc='Min. Number of Character Classes' ), - Param('krbpwdminlength?', + Int('krbpwdminlength?', cli_name='minlength', - type=ipa_types.Int(), doc='Min. Length of Password' ), ) @@ -94,7 +86,7 @@ class pwpolicy_mod(frontend.Command): api.register(pwpolicy_mod) -class pwpolicy_show(frontend.Command): +class pwpolicy_show(Command): 'Retrieve current password policy' def execute(self, *args, **kw): """ -- cgit From 86b7ebf717a99276a135a5888246cee99798a94b Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 22:29:59 -0700 Subject: Updated ra plugins module to where it can at least be imported --- ipalib/plugins/f_ra.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_ra.py b/ipalib/plugins/f_ra.py index 724cbf5e..7ac84e65 100644 --- a/ipalib/plugins/f_ra.py +++ b/ipalib/plugins/f_ra.py @@ -22,8 +22,7 @@ Frontend plugins for IPA-RA PKI operations. """ -from ipalib import api, Command, Param -from ipalib import cli +from ipalib import api, Command, Str, Int class request_certificate(Command): @@ -31,7 +30,7 @@ class request_certificate(Command): takes_args = ['csr'] - takes_options = [Param('request_type?', default='pkcs10')] + takes_options = [Str('request_type?', default=u'pkcs10')] def execute(self, csr, **options): return self.Backend.ra.request_certificate(csr, **options) @@ -85,7 +84,8 @@ class revoke_certificate(Command): takes_args = ['serial_number'] - takes_options = [Param('revocation_reason?', default=0)] + # FIXME: The default is 0. Is this really an Int param? + takes_options = [Int('revocation_reason?', default=0)] def execute(self, serial_number, **options): @@ -115,5 +115,3 @@ class take_certificate_off_hold(Command): textui.print_plain('Failed to take a revoked certificate off hold.') api.register(take_certificate_off_hold) - - -- cgit From a10144be247d109e0bcfb4d5b7812bef508ab8d6 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 22:35:13 -0700 Subject: Updated service plugins module to where it can at least be imported --- ipalib/plugins/f_service.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_service.py b/ipalib/plugins/f_service.py index a353d52e..06d6a5d0 100644 --- a/ipalib/plugins/f_service.py +++ b/ipalib/plugins/f_service.py @@ -22,27 +22,30 @@ Frontend plugins for service (Identity). """ -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param -from ipalib import api -from ipalib import errors -from ipalib import ipa_types - -class service(frontend.Object): +from ipalib import api, crud, errors +from ipalib import Object # Plugin base classes +from ipalib import Str, Flag # Parameter types + + +class service(Object): """ Service object. """ takes_params = ( - Param('principal', primary_key=True), + Str('principal', primary_key=True), ) api.register(service) class service_add(crud.Add): - 'Add a new service.' + """ + Add a new service. + """ + takes_options = ( - Param('force?', type=ipa_types.Bool(), default=False, doc='Force a service principal name'), + Flag('force', + doc='Force a service principal name', + ), ) def execute(self, principal, **kw): """ -- cgit From fdda31c50bcf79ef4e4017dc8075d55b3e5df466 Mon Sep 17 00:00:00 2001 From: Jason Gerard DeRose Date: Wed, 14 Jan 2009 22:59:44 -0700 Subject: Fixed a problem in the host plugin module; added not in TODO about using Param.query --- ipalib/plugins/f_host.py | 14 ++++++---- ipalib/plugins/f_user.py | 67 +++++++++++++++++++++++------------------------- 2 files changed, 41 insertions(+), 40 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py index bb800b50..3fcda77c 100644 --- a/ipalib/plugins/f_host.py +++ b/ipalib/plugins/f_host.py @@ -206,14 +206,18 @@ api.register(host_mod) class host_find(crud.Find): 'Search the hosts.' + takes_options = ( Flag('all', doc='Retrieve all attributes'), ) - def get_args(self): - """ - Override Find.get_args() so we can exclude the validation rules - """ - yield self.obj.primary_key.__clone__(rules=tuple()) + + # FIXME: This should no longer be needed with the Param.query kwarg. +# def get_args(self): +# """ +# Override Find.get_args() so we can exclude the validation rules +# """ +# yield self.obj.primary_key.__clone__(rules=tuple()) + def execute(self, term, **kw): ldap = self.api.Backend.ldap diff --git a/ipalib/plugins/f_user.py b/ipalib/plugins/f_user.py index 04d7c930..506ad14d 100644 --- a/ipalib/plugins/f_user.py +++ b/ipalib/plugins/f_user.py @@ -21,12 +21,9 @@ Frontend plugins for user (Identity). """ -from ipalib import frontend -from ipalib import crud -from ipalib.frontend import Param -from ipalib import api -from ipalib import errors -from ipalib import ipa_types +from ipalib import api, crud, errors +from ipalib import Object, Command # Plugin base classes +from ipalib import Str, Password, Flag, Int # Parameter types def display_user(user): @@ -48,62 +45,62 @@ def display_user(user): default_attributes = ['uid','givenname','sn','homeDirectory','loginshell'] -class user(frontend.Object): +class user(Object): """ User object. """ + takes_params = ( - Param('givenname', + Str('givenname', cli_name='first', - doc='User\'s first name', + doc="User's first name", ), - Param('sn', + Str('sn', cli_name='last', - doc='User\'s last name', + doc="User's last name", ), - Param('uid', + Str('uid', cli_name='user', primary_key=True, default_from=lambda givenname, sn: givenname[0] + sn, - normalize=lambda value: value.lower(), + normalizer=lambda value: value.lower(), ), - Param('gecos?', + Str('gecos?', doc='GECOS field', default_from=lambda uid: uid, ), - Param('homedirectory?', + Str('homedirectory?', cli_name='home', - doc='User\'s home directory', + doc="User's home directory", default_from=lambda uid: '/home/%s' % uid, ), - Param('loginshell?', + Str('loginshell?', cli_name='shell', default=u'/bin/sh', - doc='User\'s Login shell', + doc="User's Login shell", ), - Param('krbprincipalname?', cli_name='principal', - doc='User\'s Kerberos Principal name', + Str('krbprincipalname?', + cli_name='principal', + doc="User's Kerberos Principal name", default_from=lambda uid: '%s@%s' % (uid, api.env.realm), ), - Param('mailaddress?', - cli_name='mail', - doc='User\'s e-mail address', + Str('mailaddress?', + cli_name='email', + doc="User's e-mail address", ), - Param('userpassword?', + Password('userpassword?', cli_name='password', doc="Set user's password", - flags=['password'], ), - Param('groups?', + Str('groups?', doc='Add account to one or more groups (comma-separated)', ), - Param('uidnumber?', + Int('uidnumber?', cli_name='uid', - type=ipa_types.Int(), doc='The uid to use for this user. If not included one is automatically set.', ), - ) + api.register(user) @@ -254,7 +251,7 @@ api.register(user_mod) class user_find(crud.Find): 'Search the users.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Retrieve all user attributes'), + Flag('all', doc='Retrieve all user attributes'), ) def execute(self, term, **kw): ldap = self.api.Backend.ldap @@ -304,7 +301,7 @@ api.register(user_find) class user_show(crud.Get): 'Examine an existing user.' takes_options = ( - Param('all?', type=ipa_types.Bool(), doc='Retrieve all user attributes'), + Flag('all', doc='Retrieve all user attributes'), ) def execute(self, uid, **kw): """ @@ -332,11 +329,11 @@ class user_show(crud.Get): api.register(user_show) -class user_lock(frontend.Command): +class user_lock(Command): 'Lock a user account.' takes_args = ( - Param('uid', primary_key=True), + Str('uid', primary_key=True), ) def execute(self, uid, **kw): @@ -351,11 +348,11 @@ class user_lock(frontend.Command): api.register(user_lock) -class user_unlock(frontend.Command): +class user_unlock(Command): 'Unlock a user account.' takes_args = ( - Param('uid', primary_key=True), + Str('uid', primary_key=True), ) def execute(self, uid, **kw): -- cgit From bc40686b7fd8929f83a9594380a02d4104ae0cdf Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 16 Jan 2009 10:19:08 -0500 Subject: Fix rule definition to match new API --- ipalib/plugins/f_host.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_host.py b/ipalib/plugins/f_host.py index 3fcda77c..ea819a77 100644 --- a/ipalib/plugins/f_host.py +++ b/ipalib/plugins/f_host.py @@ -21,7 +21,7 @@ Frontend plugins for host/machine Identity. """ -from ipalib import api, crud, errors +from ipalib import api, crud, errors, util from ipalib import Object # Plugin base class from ipalib import Str, Flag # Parameter types @@ -42,7 +42,7 @@ def get_host(hostname): dn = ldap.find_entry_dn("serverhostname", hostname, "ipaHost") return dn -def validate_host(cn): +def validate_host(ugettext, cn): """ Require at least one dot in the hostname (to support localhost.localdomain) """ @@ -129,7 +129,7 @@ class host_add(crud.Add): # some required objectclasses # FIXME: add this attribute to cn=ipaconfig #kw['objectclass'] = config.get('ipahostobjectclasses') - kw['objectclass'] = ['nsHost', 'ipaHost'] + kw['objectclass'] = ['nsHost', 'ipaHost', 'pkiUser'] # Ensure the list of objectclasses is lower-case kw['objectclass'] = map(lambda z: z.lower(), kw.get('objectclass')) -- cgit From 8154131ce1975c9e2109e408a0a25631ea797a8c Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 16 Jan 2009 10:19:29 -0500 Subject: Use correct function for outputing a string --- ipalib/plugins/f_hostgroup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_hostgroup.py b/ipalib/plugins/f_hostgroup.py index c365c918..706712c9 100644 --- a/ipalib/plugins/f_hostgroup.py +++ b/ipalib/plugins/f_hostgroup.py @@ -281,7 +281,7 @@ class hostgroup_add_member(Command): for a in result: print "\t'%s'" % a else: - textui.print_entry("Group membership updated.") + textui.print_plain("Group membership updated.") api.register(hostgroup_add_member) -- cgit From 98ab09fafc7e24fb32b44e691eb6d6c9464197d5 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Fri, 16 Jan 2009 10:34:13 -0500 Subject: Initial implementation of netgroups --- ipalib/plugins/f_netgroup.py | 461 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100644 ipalib/plugins/f_netgroup.py (limited to 'ipalib/plugins') diff --git a/ipalib/plugins/f_netgroup.py b/ipalib/plugins/f_netgroup.py new file mode 100644 index 00000000..6ee55b0d --- /dev/null +++ b/ipalib/plugins/f_netgroup.py @@ -0,0 +1,461 @@ +# Authors: +# Rob Crittenden +# +# Copyright (C) 2009 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; version 2 only +# +# 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, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" +Frontend plugin for netgroups. +""" + +from ipalib import api, crud, errors +from ipalib import Object, Command # Plugin base classes +from ipalib import Str # Parameter types +from ipalib import uuid + +netgroup_base = "cn=ng, cn=alt" +netgroup_filter = "ipaNISNetgroup" +hostgroup_filter = "groupofnames)(!(objectclass=posixGroup)" + +def get_members(members): + """ + Return a list of members. + + It is possible that the value passed in is None. + """ + if members: + members = members.split(',') + else: + members = [] + + return members + +def find_members(ldap, failed, members, attribute, filter=None): + """ + Return 2 lists: one a list of DNs found, one a list of errors + """ + found = [] + for m in members: + if not m: continue + try: + member_dn = ldap.find_entry_dn(attribute, m, filter) + found.append(member_dn) + except errors.NotFound: + failed.append(m) + continue + + return found, failed + +def add_members(ldap, completed, members, dn, memberattr): + add_failed = [] + for member_dn in members: + try: + ldap.add_member_to_group(member_dn, dn, memberattr) + completed+=1 + except: + add_failed.append(member_dn) + + return completed, add_failed + +def add_external(ldap, completed, members, cn): + failed = [] + netgroup = api.Command['netgroup_show'](cn) + external = netgroup.get('externalhost', []) + if not isinstance(external, list): + external = [external] + external_len = len(external) + for m in members: + if not m in external: + external.append(m) + completed+=1 + else: + failed.append(m) + if len(external) > external_len: + kw = {'externalhost': external} + ldap.update(netgroup['dn'], **kw) + + return completed, failed + +def remove_members(ldap, completed, members, dn, memberattr): + remove_failed = [] + for member_dn in members: + try: + ldap.remove_member_from_group(member_dn, dn, memberattr) + completed+=1 + except: + remove_failed.append(member_dn) + + return completed, remove_failed + +def remove_external(ldap, completed, members, cn): + failed = [] + netgroup = api.Command['netgroup_show'](cn) + external = netgroup.get('externalhost', []) + if not isinstance(external, list): + external = [external] + external_len = len(external) + for m in members: + try: + external.remove(m) + completed+=1 + except ValueError: + failed.append(m) + if len(external) < external_len: + kw = {'externalhost': external} + ldap.update(netgroup['dn'], **kw) + + return completed, failed + +class netgroup(Object): + """ + netgroups object. + """ + takes_params = ( + Str('cn', + cli_name='name', + primary_key=True + ), + Str('description', + doc='Description', + ), + Str('nisdomainname?', + cli_name='domainname', + doc='Domain name', + ), + ) +api.register(netgroup) + + +class netgroup_add(crud.Add): + 'Add a new netgroup.' + + def execute(self, cn, **kw): + """ + Execute the netgroup-add operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry as it will be created in LDAP. + + :param cn: The name of the netgroup + :param kw: Keyword arguments for the other LDAP attributes. + """ + self.log.info("IPA: netgroup-add '%s'" % cn) + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + kw['cn'] = cn +# kw['dn'] = ldap.make_netgroup_dn() + kw['ipauniqueid'] = str(uuid.uuid1()) + kw['dn'] = "ipauniqueid=%s,%s,%s" % (kw['ipauniqueid'], netgroup_base, api.env.basedn) + + if not kw.get('nisdomainname', False): + kw['nisdomainname'] = api.env.domain + + # some required objectclasses + kw['objectClass'] = ['top', 'ipaAssociation', 'ipaNISNetgroup'] + + return ldap.create(**kw) + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Added netgroup "%s"' % result.get('cn')) + +api.register(netgroup_add) + + +class netgroup_del(crud.Del): + 'Delete an existing netgroup.' + + def execute(self, cn, **kw): + """Delete a netgroup. + + cn is the cn of the netgroup to delete + + The memberOf plugin handles removing the netgroup from any other + groups. + + :param cn: The name of the netgroup being removed. + :param kw: Not used. + """ + self.log.info("IPA: netgroup-del '%s'" % cn) + + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, netgroup_filter, netgroup_base) + return ldap.delete(dn) + + def output_for_cli(self, textui, result, cn): + """ + Output result of this command to command line interface. + """ + textui.print_plain('Deleted net group "%s"' % cn) + +api.register(netgroup_del) + + +class netgroup_mod(crud.Mod): + 'Edit an existing netgroup.' + def execute(self, cn, **kw): + """ + Execute the netgroup-mod operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param cn: The name of the netgroup to retrieve. + :param kw: Keyword arguments for the other LDAP attributes. + """ + self.log.info("IPA: netgroup-mod '%s'" % cn) + assert 'cn' not in kw + assert 'dn' not in kw + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, netgroup_filter, netgroup_base) + return ldap.update(dn, **kw) + + def output_for_cli(self, textui, result, cn, **options): + """ + Output result of this command to command line interface. + """ + textui.print_name(self.name) + textui.print_entry(result) + textui.print_dashed('Updated netgroup "%s"' % result['cn']) + +api.register(netgroup_mod) + + +class netgroup_find(crud.Find): + 'Search the netgroups.' + def execute(self, term, **kw): + ldap = self.api.Backend.ldap + + search_fields = ['ipauniqueid','description','nisdomainname','cn'] + + search_kw = {} + for s in search_fields: + search_kw[s] = term + + search_kw['objectclass'] = netgroup_filter + search_kw['base'] = netgroup_base + return ldap.search(**search_kw) + + def output_for_cli(self, textui, result, *args, **options): + counter = result[0] + groups = result[1:] + if counter == 0 or len(groups) == 0: + textui.print_plain("No entries found") + return + if len(groups) == 1: + textui.print_entry(groups[0]) + return + textui.print_name(self.name) + for g in groups: + textui.print_entry(g) + textui.print_plain('') + if counter == -1: + textui.print_plain('These results are truncated.') + textui.print_plain('Please refine your search and try again.') + textui.print_count(groups, '%d netgroups matched') + +api.register(netgroup_find) + + +class netgroup_show(crud.Get): + 'Examine an existing netgroup.' + def execute(self, cn, **kw): + """ + Execute the netgroup-show operation. + + The dn should not be passed as a keyword argument as it is constructed + by this method. + + Returns the entry + + :param cn: The name of the netgroup to retrieve. + :param kw: Unused + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, netgroup_filter, netgroup_base) + return ldap.retrieve(dn) + + def output_for_cli(self, textui, result, *args, **options): + textui.print_entry(result) + +api.register(netgroup_show) + +class netgroup_add_member(Command): + 'Add a member to a group.' + takes_args = ( + Str('cn', + cli_name='name', + primary_key=True + ), + ) + takes_options = ( + Str('hosts?', doc='comma-separated list of hosts to add'), + Str('hostgroups?', doc='comma-separated list of host groups to add'), + Str('users?', doc='comma-separated list of users to add'), + Str('groups?', doc='comma-separated list of groups to add'), + ) + + def execute(self, cn, **kw): + """ + Execute the netgroup-add-member operation. + + Returns the updated group entry + + :param cn: The netgroup name to add new members to. + :param kw: hosts is a comma-separated list of hosts to add + :param kw: hostgroups is a comma-separated list of host groups to add + :param kw: users is a comma-separated list of users to add + :param kw: groups is a comma-separated list of host to add + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, netgroup_filter, netgroup_base) + add_failed = [] + to_add = [] + completed = 0 + + # Hosts + members = get_members(kw.get('hosts', '')) + (to_add, add_failed) = find_members(ldap, add_failed, members, "cn", "ipaHost") + + # If a host is not found we'll consider it an externalHost. It will + # be up to the user to handle typos + if add_failed: + (completed, failed) = add_external(ldap, completed, add_failed, cn) + add_failed = failed + + (completed, failed) = add_members(ldap, completed, to_add, dn, 'memberhost') + add_failed+=failed + + # Host groups + members = get_members(kw.get('hostgroups', '')) + (to_add, add_failed) = find_members(ldap, add_failed, members, "cn", hostgroup_filter) + (completed, failed) = add_members(ldap, completed, to_add, dn, 'memberhost') + add_failed+=failed + + # User + members = get_members(kw.get('users', '')) + (to_add, add_failed) = find_members(ldap, add_failed, members, "uid") + (completed, failed) = add_members(ldap, completed, to_add, dn, 'memberuser') + add_failed+=failed + + # Groups + members = get_members(kw.get('groups', '')) + (to_add, add_failed) = find_members(ldap, add_failed, members, "cn", "posixGroup") + (completed, failed) = add_members(ldap, completed, to_add, dn, 'memberuser') + add_failed+=failed + + return add_failed + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + if result: + textui.print_plain("These entries failed to add to the group:") + for a in result: + print "\t'%s'" % a + else: + textui.print_plain("netgroup membership updated.") + +api.register(netgroup_add_member) + + +class netgroup_remove_member(Command): + 'Remove a member from a group.' + takes_args = ( + Str('cn', + cli_name='name', + primary_key=True + ), + ) + takes_options = ( + Str('hosts?', doc='comma-separated list of hosts to remove'), + Str('hostgroups?', doc='comma-separated list of groups to remove'), + Str('users?', doc='comma-separated list of users to remove'), + Str('groups?', doc='comma-separated list of groups to remove'), + ) + def execute(self, cn, **kw): + """ + Execute the group-remove-member operation. + + Returns the members that could not be added + + :param cn: The group name to add new members to. + :param kw: hosts is a comma-separated list of hosts to remove + :param kw: hostgroups is a comma-separated list of host groups to remove + :param kw: users is a comma-separated list of users to remove + :param kw: groups is a comma-separated list of host to remove + """ + ldap = self.api.Backend.ldap + dn = ldap.find_entry_dn("cn", cn, netgroup_filter, netgroup_base) + remove_failed = [] + to_remove = [] + completed = 0 + + # Hosts + members = get_members(kw.get('hosts', '')) + (to_remove, remove_failed) = find_members(ldap, remove_failed, members, "cn", "ipaHost") + + # If a host is not found we'll consider it an externalHost. It will + # be up to the user to handle typos + if remove_failed: + (completed, failed) = remove_external(ldap, completed, remove_failed, cn) + remove_failed = failed + + (completed, failed) = remove_members(ldap, completed, to_remove, dn, 'memberhost') + remove_failed+=failed + + # Host groups + members = get_members(kw.get('hostgroups', '')) + (to_remove, remove_failed) = find_members(ldap, remove_failed, members, "cn", hostgroup_filter) + (completed, failed) = remove_members(ldap, completed, to_remove, dn, 'memberhost') + remove_failed+=failed + + # User + members = get_members(kw.get('users', '')) + (to_remove, remove_failed) = find_members(ldap, remove_failed, members, "uid") + (completed, failed) = remove_members(ldap, completed, to_remove, dn, 'memberuser') + remove_failed+=failed + + # Groups + members = get_members(kw.get('groups', '')) + (to_remove, remove_failed) = find_members(ldap, remove_failed, members, "cn", "posixGroup") + (completed, failed) = remove_members(ldap, completed, to_remove, dn, 'memberuser') + remove_failed+=failed + + return remove_failed + + def output_for_cli(self, textui, result, *args, **options): + """ + Output result of this command to command line interface. + """ + if result: + textui.print_plain("These entries failed to be removed from the group:") + for a in result: + print "\t'%s'" % a + else: + textui.print_plain("netgroup membership updated.") + +api.register(netgroup_remove_member) -- cgit