# See the License for the specific language governing permissions and
# limitations under the License.
-from ncclient.rpc import RPC
-from ncclient.content import iselement
+from copy import deepcopy
+
+from ncclient import content
+
+from rpc import RPC
import util
+import logging
+logger = logging.getLogger('ncclient.operations.edit')
+
+
+
+"Operations related to changing device configuration"
+
class EditConfig(RPC):
-
- SPEC = {
- 'tag': 'edit-config',
- 'children': [ ]
- }
-
- 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()
- params = spec['children']
- params.append({'tag': 'target', 'children': util.store_or_url(target, target_url)})
- params.append({'tag': 'config', 'children': config})
- if default_operation is not None:
- params.append({'tag': 'default-operation', 'text': default_operation})
- if test_option is not None:
- params.append({'tag': 'test-option', 'text': test_option})
+
+ # TESTED
+
+ "*<edit-config>* RPC"
+
+ SPEC = {'tag': 'edit-config', 'subtree': []}
+
+ 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(util.store_or_url('target', target, self._assert))
if error_option is not None:
- params.append({'tag': 'test-option', 'text': test_option})
+ if error_option == 'rollback-on-error':
+ self._assert(':rollback-on-error')
+ subtree.append({
+ 'tag': 'error-option',
+ 'text': error_option
+ })
+ if test_option is not None:
+ self._assert(':validate')
+ subtree.append({
+ 'tag': 'test-option',
+ 'text': test_option
+ })
+ if default_operation is not None:
+ subtree.append({
+ 'tag': 'default-operation',
+ 'text': default_operation
+ })
+ subtree.append(content.validated_element(config, ('config', content.qualify('config'))))
+ return self._request(spec)
class DeleteConfig(RPC):
-
- SPEC = {
- 'tag': 'delete-config',
- 'children': [ { 'tag': 'target', 'children': None } ]
- }
-
- def request(self, target=None, target_url=None):
- spec = DeleteConfig.SPEC.copy()
- spec['children'][0]['children'] = util.store_or_url(target, target_url)
+
+ # TESTED
+
+ "*<delete-config>* RPC"
+
+ SPEC = {'tag': 'delete-config', 'subtree': []}
+
+ 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):
-
- SPEC = {
- 'tag': 'copy-config',
- 'children': [
- { 'tag': 'source', 'children': {'tag': None } },
- { 'tag': 'target', 'children': {'tag': None } }
- ]
- }
-
- def request(self, source=None, source_url=None, target=None, target_url=None):
- spec = CopyConfig.SPEC.copy()
- spec['children'][0]['children'] = util.store_or_url(source, source_url)
- spec['children'][1]['children'] = util.store_or_url(target, target_url)
+
+ # TESTED
+
+ "*<copy-config>* RPC"
+
+ SPEC = {'tag': 'copy-config', 'subtree': []}
+
+ 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):
-
- 'config attr shd not include <config> root'
-
+
+ # TESTED
+
+ "*<validate>* RPC. Depends on the *:validate* capability."
+
DEPENDS = [':validate']
-
- SPEC = {
- 'tag': 'validate',
- 'children': []
- }
-
- def request(self, source=None, config=None):
- util.one_of(source, capability)
- spec = SPEC.copy()
- if source is not None:
- spec['children'].append({
- 'tag': 'source', 'children': {'tag': source}
- })
- else:
- spec['children'].append({'tag': 'config', 'children': config})
+
+ SPEC = {'tag': 'validate', 'subtree': []}
+
+ 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
+ })
return self._request(spec)
class Commit(RPC):
-
+
+ # TESTED
+
+ "*<commit>* RPC. Depends on the *:candidate* capability."
+
DEPENDS = [':candidate']
-
- SPEC = {'tag': 'commit', 'children': [] }
-
+
+ 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')
- children = spec['children']
- children.append({'tag': 'confirmed'})
+ spec['subtree'].append({'tag': 'confirmed'})
if timeout is not None:
- children.append({
+ spec['subtree'].append({
'tag': 'confirm-timeout',
'text': timeout
})
class DiscardChanges(RPC):
-
+
+ # TESTED
+
+ "*<discard-changes>* RPC. Depends on the *:candidate* capability."
+
DEPENDS = [':candidate']
-
+
SPEC = {'tag': 'discard-changes'}
-
- request = lambda self: self._request(DiscardChanges.SPEC)
+
+ def request(self):
+ ":seealso: :ref:`return`"
+ return self._request(DiscardChanges.SPEC)