diff options
Diffstat (limited to 'ipalib')
-rw-r--r-- | ipalib/__init__.py | 51 | ||||
-rw-r--r-- | ipalib/cli.py | 4 | ||||
-rw-r--r-- | ipalib/frontend.py | 18 | ||||
-rw-r--r-- | ipalib/plugins/aci.py | 2 | ||||
-rw-r--r-- | ipalib/plugins/automount.py | 2 | ||||
-rw-r--r-- | ipalib/plugins/batch.py | 1 | ||||
-rw-r--r-- | ipalib/plugins/cert.py | 12 | ||||
-rw-r--r-- | ipalib/plugins/dns.py | 4 | ||||
-rw-r--r-- | ipalib/plugins/hbacrule.py | 4 | ||||
-rw-r--r-- | ipalib/plugins/internal.py | 2 | ||||
-rw-r--r-- | ipalib/plugins/passwd.py | 2 | ||||
-rw-r--r-- | ipalib/plugins/ping.py | 2 | ||||
-rw-r--r-- | ipalib/plugins/selinuxusermap.py | 4 | ||||
-rw-r--r-- | ipalib/plugins/sudorule.py | 4 |
14 files changed, 61 insertions, 51 deletions
diff --git a/ipalib/__init__.py b/ipalib/__init__.py index 8bf37f048..aab740081 100644 --- a/ipalib/__init__.py +++ b/ipalib/__init__.py @@ -134,7 +134,7 @@ implement a ``run()`` method, like this: >>> class my_command(Command): ... """My example plugin with run().""" ... -... def run(self): +... def run(self, **options): ... return dict(result='My run() method was called!') ... >>> api = create_api() @@ -174,17 +174,22 @@ For example, say you have a command plugin like this: >>> class my_command(Command): ... """Forwarding vs. execution.""" ... -... def forward(self): +... def forward(self, **options): ... return dict( ... result='forward(): in_server=%r' % self.env.in_server ... ) ... -... def execute(self): +... def execute(self, **options): ... return dict( ... result='execute(): in_server=%r' % self.env.in_server ... ) ... +The ``options`` will contain a dict of command options. One option is added +automatically: ``version``. It contains the API version of the client. +In order to maintain forward compatibility, you should always specify the +API version current at the time you're writing your client. + If ``my_command`` is loaded in a *client* context, ``forward()`` will be called: @@ -192,7 +197,7 @@ called: >>> api.env.in_server = False # run() will dispatch to forward() >>> api.register(my_command) >>> api.finalize() ->>> api.Command.my_command() # Call your command plugin +>>> api.Command.my_command(version=u'2.47') # Call your command plugin {'result': 'forward(): in_server=False'} On the other hand, if ``my_command`` is loaded in a *server* context, @@ -202,7 +207,7 @@ On the other hand, if ``my_command`` is loaded in a *server* context, >>> api.env.in_server = True # run() will dispatch to execute() >>> api.register(my_command) >>> api.finalize() ->>> api.Command.my_command() # Call your command plugin +>>> api.Command.my_command(version=u'2.47') # Call your command plugin {'result': 'execute(): in_server=True'} Normally there should be no reason to override `frontend.Command.forward()`, @@ -314,7 +319,7 @@ Second, we have our frontend plugin, the command: >>> class my_command(Command): ... """My example command plugin.""" ... -... def execute(self): +... def execute(self, **options): ... """Implemented against Backend.my_backend""" ... return dict(result=self.Backend.my_backend.do_stuff()) ... @@ -324,7 +329,7 @@ Lastly, we call ``api.finalize()`` and see what happens when we call ``my_command()``: >>> api.finalize() ->>> api.Command.my_command() +>>> api.Command.my_command(version=u'2.47') {'result': 'my_backend.do_stuff() indeed did do stuff!'} When not in a server context, ``my_command.execute()`` never gets called, so @@ -337,11 +342,11 @@ example: >>> class my_command(Command): ... """My example command plugin.""" ... -... def execute(self): +... def execute(self, **options): ... """Same as above.""" ... return dict(result=self.Backend.my_backend.do_stuff()) ... -... def forward(self): +... def forward(self, **options): ... return dict(result='Just my_command.forward() getting called here.') ... >>> api.register(my_command) @@ -371,7 +376,7 @@ several other commands in a single operation. For example: >>> class meta_command(Command): ... """My meta-command plugin.""" ... -... def execute(self): +... def execute(self, **options): ... """Calls command_1(), command_2()""" ... msg = '%s; %s.' % ( ... self.Command.command_1()['result'], @@ -379,18 +384,18 @@ several other commands in a single operation. For example: ... ) ... return dict(result=msg) >>> class command_1(Command): -... def execute(self): +... def execute(self, **options): ... return dict(result='command_1.execute() called') ... >>> class command_2(Command): -... def execute(self): +... def execute(self, **options): ... return dict(result='command_2.execute() called') ... >>> api.register(meta_command) >>> api.register(command_1) >>> api.register(command_2) >>> api.finalize() ->>> api.Command.meta_command() +>>> api.Command.meta_command(version=u'2.47') {'result': 'command_1.execute() called; command_2.execute() called.'} Because this is quite useful, we are going to revise our golden rule somewhat: @@ -425,9 +430,9 @@ For example: >>> api.env.in_server = True >>> api.register(nudge) >>> api.finalize() ->>> api.Command.nudge(u'Jason') +>>> api.Command.nudge(u'Jason', version=u'2.47') {'result': u'Jason, go write more documentation!'} ->>> api.Command.nudge(u'Jason', stuff=u'unit tests') +>>> api.Command.nudge(u'Jason', stuff=u'unit tests', version=u'2.47') {'result': u'Jason, go write more unit tests!'} The ``args`` and ``options`` attributes are `plugable.NameSpace` instances @@ -438,25 +443,27 @@ containing a command's arguments and options, respectively, as you can see: >>> api.Command.nudge.args.programmer Str('programmer') >>> list(api.Command.nudge.options) # Iterates through option names -['stuff'] +['stuff', 'version'] >>> api.Command.nudge.options.stuff Str('stuff', default=u'documentation') >>> api.Command.nudge.options.stuff.default u'documentation' +The 'version' option is added to commands automatically. + The arguments and options must not contain colliding names. They are both merged together into the ``params`` attribute, another `plugable.NameSpace` instance, as you can see: >>> api.Command.nudge.params -NameSpace(<2 members>, sort=False) +NameSpace(<3 members>, sort=False) >>> list(api.Command.nudge.params) # Iterates through the param names -['programmer', 'stuff'] +['programmer', 'stuff', 'version'] When calling a command, its positional arguments can also be provided as keyword arguments, and in any order. For example: ->>> api.Command.nudge(stuff=u'lines of code', programmer=u'Jason') +>>> api.Command.nudge(stuff=u'lines of code', programmer=u'Jason', version=u'2.47') {'result': u'Jason, go write more lines of code!'} When a command plugin is called, the values supplied for its parameters are @@ -669,7 +676,7 @@ For example: ... ... takes_args = 'color' ... -... def execute(self, color): +... def execute(self, color, **options): ... """Uses self.log.error()""" ... if color not in ('red', 'blue', 'green'): ... self.log.error("I don't have %s paint!", color) # Log error @@ -746,14 +753,14 @@ For example: >>> class motd(Command): ... """Print message of the day.""" ... -... def execute(self): +... def execute(self, **options): ... return dict(result=self.env.message) ... >>> api = create_api() >>> api.bootstrap(in_server=True, message='Hello, world!') >>> api.register(motd) >>> api.finalize() ->>> api.Command.motd() +>>> api.Command.motd(version=u'2.47') {'result': u'Hello, world!'} Also see the `plugable.API.bootstrap_with_global_options()` method. diff --git a/ipalib/cli.py b/ipalib/cli.py index 3d59e4a0a..f1d2f8743 100644 --- a/ipalib/cli.py +++ b/ipalib/cli.py @@ -755,7 +755,7 @@ class help(frontend.Local): super(help, self)._on_finalize() - def run(self, key, outfile=None): + def run(self, key, outfile=None, **options): if outfile is None: outfile = sys.stdout writer = self._writer(outfile) @@ -872,7 +872,7 @@ class console(frontend.Command): has_output = tuple() - def run(self): + def run(self, **options): code.interact( '(Custom IPA interactive Python console)', local=dict(api=self.api) diff --git a/ipalib/frontend.py b/ipalib/frontend.py index 52ddf28c7..c27ff1389 100644 --- a/ipalib/frontend.py +++ b/ipalib/frontend.py @@ -526,7 +526,6 @@ class Command(HasParam): yield (name, options.pop(name)) # If any options remain, they are either internal or unknown unused_keys = set(options).difference(self.internal_options) - unused_keys.discard('version') if unused_keys: raise OptionError(_('Unknown option: %(option)s'), option=unused_keys.pop()) @@ -743,7 +742,8 @@ class Command(HasParam): if self.api.env.in_server: if 'version' in options: self.verify_client_version(options['version']) - del options['version'] + else: + options['version'] = API_VERSION return self.execute(*args, **options) return self.forward(*args, **options) @@ -897,12 +897,12 @@ class Command(HasParam): exclude='webui', flags=['no_output'], ) - yield Str('version?', - doc=_('Client version. Used to determine if server will accept request.'), - exclude='webui', - flags=['no_option', 'no_output'], - ) - return + break + yield Str('version?', + doc=_('Client version. Used to determine if server will accept request.'), + exclude='webui', + flags=['no_option', 'no_output'], + ) def validate_output(self, output): """ @@ -1282,7 +1282,7 @@ class Method(Attribute, Command): >>> from ipalib import create_api >>> api = create_api() >>> class user_add(Method): - ... def run(self): + ... def run(self, **options): ... return dict(result='Added the user!') ... >>> class user(Object): diff --git a/ipalib/plugins/aci.py b/ipalib/plugins/aci.py index 7c4e8a549..a97bb48b0 100644 --- a/ipalib/plugins/aci.py +++ b/ipalib/plugins/aci.py @@ -566,7 +566,7 @@ class aci_del(crud.Delete): takes_options = (_prefix_option,) - def execute(self, aciname, aciprefix): + def execute(self, aciname, aciprefix, **options): """ Execute the aci-delete operation. diff --git a/ipalib/plugins/automount.py b/ipalib/plugins/automount.py index 19b60905d..fcda0a102 100644 --- a/ipalib/plugins/automount.py +++ b/ipalib/plugins/automount.py @@ -889,7 +889,7 @@ class automountkey_del(LDAPDelete): ), ) def get_options(self): - for option in self.takes_options: + for option in super(automountkey_del, self).get_options(): if option.name == 'continue': # TODO: hide for now - remove in future major release yield option.clone(exclude='webui', diff --git a/ipalib/plugins/batch.py b/ipalib/plugins/batch.py index db9c08f10..5fd5943f6 100644 --- a/ipalib/plugins/batch.py +++ b/ipalib/plugins/batch.py @@ -95,6 +95,7 @@ class batch(Command): a, kw = arg['params'] newkw = dict((str(k), v) for k, v in kw.iteritems()) params = api.Command[name].args_options_2_params(*a, **newkw) + newkw.setdefault('version', options['version']) result = api.Command[name](*a, **newkw) self.info( diff --git a/ipalib/plugins/cert.py b/ipalib/plugins/cert.py index 51493c34e..6b84c7235 100644 --- a/ipalib/plugins/cert.py +++ b/ipalib/plugins/cert.py @@ -306,8 +306,7 @@ class cert_request(VirtualCommand): ldap = self.api.Backend.ldap2 principal = kw.get('principal') add = kw.get('add') - del kw['principal'] - del kw['add'] + request_type = kw.get('request_type') service = None """ @@ -414,7 +413,8 @@ class cert_request(VirtualCommand): api.Command['host_mod'](hostname, usercertificate=None) # Request the certificate - result = self.Backend.ra.request_certificate(csr, **kw) + result = self.Backend.ra.request_certificate( + csr, request_type=request_type) cert = x509.load_certificate(result['certificate']) result['issuer'] = unicode(cert.issuer) result['valid_not_before'] = unicode(cert.valid_not_before_str) @@ -596,10 +596,12 @@ class cert_revoke(VirtualCommand): result = api.Command['cert_show'](unicode(serial_number))['result'] except errors.NotImplementedError: pass - if kw['revocation_reason'] == 7: + revocation_reason = kw['revocation_reason'] + if revocation_reason == 7: raise errors.CertificateOperationError(error=_('7 is not a valid revocation reason')) return dict( - result=self.Backend.ra.revoke_certificate(serial_number, **kw) + result=self.Backend.ra.revoke_certificate( + serial_number, revocation_reason=revocation_reason) ) api.register(cert_revoke) diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py index c329c1003..61c2de321 100644 --- a/ipalib/plugins/dns.py +++ b/ipalib/plugins/dns.py @@ -2730,13 +2730,13 @@ class dnsrecord_del(LDAPUpdate): error=_('Zone record \'%s\' cannot be deleted') \ % _dns_zone_record ) - return self.obj.methods.delentry(*keys) + return self.obj.methods.delentry(*keys, version=options['version']) result = super(dnsrecord_del, self).execute(*keys, **options) if getattr(context, 'del_all', False) and not \ self.obj.is_pkey_zone_record(*keys): - return self.obj.methods.delentry(*keys) + return self.obj.methods.delentry(*keys, version=options['version']) return result def post_callback(self, ldap, dn, entry_attrs, *keys, **options): diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py index 0b1e8b83c..8bc4c6dfc 100644 --- a/ipalib/plugins/hbacrule.py +++ b/ipalib/plugins/hbacrule.py @@ -303,7 +303,7 @@ class hbacrule_enable(LDAPQuery): msg_summary = _('Enabled HBAC rule "%(value)s"') has_output = output.standard_value - def execute(self, cn): + def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) @@ -330,7 +330,7 @@ class hbacrule_disable(LDAPQuery): msg_summary = _('Disabled HBAC rule "%(value)s"') has_output = output.standard_value - def execute(self, cn): + def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) diff --git a/ipalib/plugins/internal.py b/ipalib/plugins/internal.py index cfb5d60f9..e9fc9de40 100644 --- a/ipalib/plugins/internal.py +++ b/ipalib/plugins/internal.py @@ -682,7 +682,7 @@ class i18n_messages(Command): has_output = ( Output('messages', dict, doc=_('Dict of I18N messages')), ) - def execute(self): + def execute(self, **options): return dict([("messages",json_serialize(self.messages))]) def output_for_cli(self, textui, result, *args, **options): diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py index 68aa3ebb0..280517cd9 100644 --- a/ipalib/plugins/passwd.py +++ b/ipalib/plugins/passwd.py @@ -88,7 +88,7 @@ class passwd(Command): has_output = output.standard_value msg_summary = _('Changed password for "%(value)s"') - def execute(self, principal, password, current_password): + def execute(self, principal, password, current_password, **options): """ Execute the passwd operation. diff --git a/ipalib/plugins/ping.py b/ipalib/plugins/ping.py index 0da07e0b4..e9dc28fea 100644 --- a/ipalib/plugins/ping.py +++ b/ipalib/plugins/ping.py @@ -58,7 +58,7 @@ class ping(Command): output.summary, ) - def execute(self): + def execute(self, **options): """ A possible enhancement would be to take an argument and echo it back but a fixed value works for now. diff --git a/ipalib/plugins/selinuxusermap.py b/ipalib/plugins/selinuxusermap.py index 32c55850b..60eb053a1 100644 --- a/ipalib/plugins/selinuxusermap.py +++ b/ipalib/plugins/selinuxusermap.py @@ -394,7 +394,7 @@ class selinuxusermap_enable(LDAPQuery): msg_summary = _('Enabled SELinux User Map "%(value)s"') has_output = output.standard_value - def execute(self, cn): + def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) @@ -421,7 +421,7 @@ class selinuxusermap_disable(LDAPQuery): msg_summary = _('Disabled SELinux User Map "%(value)s"') has_output = output.standard_value - def execute(self, cn): + def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py index 111080999..878033f0e 100644 --- a/ipalib/plugins/sudorule.py +++ b/ipalib/plugins/sudorule.py @@ -321,7 +321,7 @@ api.register(sudorule_show) class sudorule_enable(LDAPQuery): __doc__ = _('Enable a Sudo Rule.') - def execute(self, cn): + def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) @@ -345,7 +345,7 @@ api.register(sudorule_enable) class sudorule_disable(LDAPQuery): __doc__ = _('Disable a Sudo Rule.') - def execute(self, cn): + def execute(self, cn, **options): ldap = self.obj.backend dn = self.obj.get_dn(cn) |