X-Git-Url: https://code.grnet.gr/git/ncclient/blobdiff_plain/ebf2bbc6f6453ebce54858a70b1dc7f110eaa194..2abf95229fe31480f4f62944b8cc61e1f9ad4f8d:/ncclient/operations/edit.py diff --git a/ncclient/operations/edit.py b/ncclient/operations/edit.py index 538e419..f123d50 100644 --- a/ncclient/operations/edit.py +++ b/ncclient/operations/edit.py @@ -12,35 +12,58 @@ # See the License for the specific language governing permissions and # limitations under the License. +from copy import deepcopy + from ncclient import content from rpc import RPC import util -"Operations related to configuration editing" +import logging +logger = logging.getLogger('ncclient.operations.edit') + + + +"Operations related to changing device configuration" class EditConfig(RPC): - - # tested: no - # combed: yes - + + # TESTED + + "** RPC" + SPEC = {'tag': 'edit-config', 'subtree': []} - - def request(self, target=None, target_url=None, config=None, - default_operation=None, test_option=None, error_option=None): - util.one_of(target, target_url) - spec = EditConfig.SPEC.copy() + + def request(self, target, config, default_operation=None, test_option=None, + error_option=None): + """ + :arg target: see :ref:`source_target` + :type target: string + + :arg config: a config element in :ref:`dtree` + :type config: `string` or `dict` or :class:`~xml.etree.ElementTree.Element` + + :arg default_operation: optional; one of {'merge', 'replace', 'none'} + :type default_operation: `string` + + :arg error_option: optional; one of {'stop-on-error', 'continue-on-error', 'rollback-on-error'}. Last option depends on the *:rollback-on-error* capability + :type error_option: string + + :arg test_option: optional; one of {'test-then-set', 'set'}. Depends on *:validate* capability. + :type test_option: string + + :seealso: :ref:`return` + """ + spec = deepcopy(EditConfig.SPEC) subtree = spec['subtree'] - subtree.append({ - 'tag': 'target', - 'subtree': util.store_or_url(target, target_url, self._assert) - }) - subtree.append(content.root_ensured(config, 'config')) - if default_operation is not None: + subtree.append(util.store_or_url('target', target, self._assert)) + if error_option is not None: + if error_option == 'rollback-on-error': + self._assert(':rollback-on-error') subtree.append({ - 'tag': 'default-operation', - 'text': default_operation + 'tag': 'error-option', + 'text': error_option }) if test_option is not None: self._assert(':validate') @@ -48,89 +71,115 @@ class EditConfig(RPC): 'tag': 'test-option', 'text': test_option }) - if error_option is not None: - if error_option == 'rollback-on-error': - self._assert(':rollback-on-error') + if default_operation is not None: subtree.append({ - 'tag': 'error-option', - 'text': error_option + 'tag': 'default-operation', + 'text': default_operation }) - + subtree.append(content.validated_element(config, ('config', content.qualify('config')))) + return self._request(spec) class DeleteConfig(RPC): - - # tested: no - # combed: yes - + + # TESTED + + "** RPC" + SPEC = {'tag': 'delete-config', 'subtree': []} - - def request(self, target=None, target_url=None): - spec = DeleteConfig.SPEC.copy() - spec['subtree'].append({ - 'tag': 'target', - 'subtree': util.store_or_url(target, target_url, self._assert) - }) + + def request(self, target): + """ + :arg target: See :ref:`source_target` + :type target: `string` or `dict` or :class:`~xml.etree.ElementTree.Element` + + :seealso: :ref:`return` + """ + spec = deepcopy(DeleteConfig.SPEC) + spec['subtree'].append(util.store_or_url('target', target, self._assert)) return self._request(spec) class CopyConfig(RPC): - - # tested: no - # combed: yes - + + # TESTED + + "** RPC" + SPEC = {'tag': 'copy-config', 'subtree': []} - - def request(self, source=None, source_url=None, target=None, target_url=None): - spec = CopyConfig.SPEC.copy() - spec['subtree'].append({ - 'tag': 'source', - 'subtree': util.store_or_url(source, source_url, self._assert) - }) - spec['subtree'].append({ - 'tag': 'target', - 'subtree': util.store_or_url(target, target_url, self._assert) - }) + + def request(self, source, target): + """ + :arg source: See :ref:`source_target` + :type source: `string` or `dict` or :class:`~xml.etree.ElementTree.Element` + + :arg target: See :ref:`source_target` + :type target: `string` or `dict` or :class:`~xml.etree.ElementTree.Element` + + :seealso: :ref:`return` + """ + spec = deepcopy(CopyConfig.SPEC) + spec['subtree'].append(util.store_or_url('target', target, self._assert)) + spec['subtree'].append(util.store_or_url('source', source, self._assert)) return self._request(spec) class Validate(RPC): - - # tested: no - # combed: yes - - 'config attr shd not include root' - + + # TESTED + + "** RPC. Depends on the *:validate* capability." + DEPENDS = [':validate'] - + SPEC = {'tag': 'validate', 'subtree': []} - - def request(self, source=None, source_url=None, config=None): - util.one_of(source, source_url, config) - spec = Validate.SPEC.copy() - if config is None: - spec['subtree'].append({ - 'tag': 'source', - 'subtree': util.store_or_url(source, source_url, self._assert) + + def request(self, source): + """ + :arg source: See :ref:`source_target` + :type source: `string` or `dict` or :class:`~xml.etree.ElementTree.Element` + + :seealso: :ref:`return` + """ + spec = deepcopy(Validate.SPEC) + try: + src = content.validated_element(source, ('config', content.qualify('config'))) + except Exception as e: + logger.debug(e) + src = util.store_or_url('source', source, self._assert) + spec['subtree'].append({ + 'tag': 'source', + 'subtree': src }) - else: - spec['subtree'].append(content.root_ensured(config, 'config')) return self._request(spec) class Commit(RPC): - - # tested: no - # combed: yes - + + # TESTED + + "** RPC. Depends on the *:candidate* capability." + DEPENDS = [':candidate'] - + SPEC = {'tag': 'commit', 'subtree': []} - + def _parse_hook(self): pass - + def request(self, confirmed=False, timeout=None): - spec = SPEC.copy() + """ + Requires *:confirmed-commit* capability if *confirmed* argument is + :const:`True`. + + :arg confirmed: optional; request a confirmed commit + :type confirmed: `bool` + + :arg timeout: specify timeout for confirmed commit + :type timeout: `int` + + :seealso: :ref:`return` + """ + spec = deepcopy(Commit.SPEC) if confirmed: self._assert(':confirmed-commit') spec['subtree'].append({'tag': 'confirmed'}) @@ -142,29 +191,16 @@ class Commit(RPC): return self._request(Commit.SPEC) -class ConfirmedCommit(Commit): - "psuedo-op" - - # tested: no - # combed: yes - - DEPENDS = [':candidate', ':confirmed-commit'] - - def request(self, timeout=None): - "Commit changes; requireing that a confirming commit follow" - return Commit.request(self, confirmed=True, timeout=timeout) - - def confirm(self): - "Make the confirming commit" - return Commit.request(self, confirmed=True) +class DiscardChanges(RPC): + # TESTED + + "** RPC. Depends on the *:candidate* capability." -class DiscardChanges(RPC): - - # tested: no - # combed: yes - DEPENDS = [':candidate'] - + SPEC = {'tag': 'discard-changes'} + def request(self): + ":seealso: :ref:`return`" + return self._request(DiscardChanges.SPEC)