summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Sprygada <psprygada@ansible.com>2016-08-20 06:57:13 -0400
committerPeter Sprygada <psprygada@ansible.com>2016-08-20 06:57:13 -0400
commit7c928e878be2e78621d637c549daed8936d38dc7 (patch)
tree6c8b1251dee95ee0a9fdf90f04f1b436dafb8cfb
parentfa395bee7b3c227f1808ee3bab9b72d0d6be3b2b (diff)
downloadansible-7c928e878be2e78621d637c549daed8936d38dc7.tar.gz
moves Cli and Command class from network to netcmd module
This restructure moves the Cli object to netcmd and includes a roll up of inor bugfix updates to CommandRunner * CommandRunner now only allows one instance of a command in the stack and raise an exception if a duplidate command is detected * CommandRunner now caches returns based on command and output * CommandRunner is not responsible for creating Command instances
-rw-r--r--lib/ansible/module_utils/netcmd.py202
1 files changed, 143 insertions, 59 deletions
diff --git a/lib/ansible/module_utils/netcmd.py b/lib/ansible/module_utils/netcmd.py
index fc77af8d12..b5a5637f31 100644
--- a/lib/ansible/module_utils/netcmd.py
+++ b/lib/ansible/module_utils/netcmd.py
@@ -33,6 +33,149 @@ import shlex
from ansible.module_utils.basic import BOOLEANS_TRUE, BOOLEANS_FALSE
+def to_list(val):
+ if isinstance(val, (list, tuple)):
+ return list(val)
+ elif val is not None:
+ return [val]
+ else:
+ return list()
+
+class FailedConditionsError(Exception):
+ def __init__(self, msg, failed_conditions):
+ super(FailedConditionsError, self).__init__(msg)
+ self.failed_conditions = failed_conditions
+
+class AddCommandError(Exception):
+ def __init__(self, msg, command):
+ super(AddCommandError, self).__init__(msg)
+ self.command = command
+
+class Cli(object):
+
+ def __init__(self, connection):
+ self.connection = connection
+ self.default_output = connection.default_output or 'text'
+ self._commands = list()
+
+ @property
+ def commands(self):
+ return [str(c) for c in self._commands]
+
+ def __call__(self, commands, output=None):
+ objects = list()
+ for cmd in commands:
+ objects.append(self.to_command(cmd, output))
+ return self.connection.run_commands(objects)
+
+ def to_command(self, command, output=None, prompt=None, response=None):
+ output = output or self.default_output
+ if isinstance(command, Command):
+ return command
+ elif isinstance(command, dict):
+ output = cmd.get('output') or output
+ cmd = cmd['command']
+ if isinstance(prompt, basestring):
+ prompt = re.compile(re.escape(prompt))
+ return Command(command, output, prompt=prompt, response=response)
+
+ def add_commands(self, commands, output=None, **kwargs):
+ for cmd in commands:
+ self._commands.append(self.to_command(cmd, output, **kwargs))
+
+ def run_commands(self):
+ responses = self.connection.run_commands(self._commands)
+ for resp, cmd in itertools.izip(responses, self._commands):
+ cmd.response = resp
+
+ # wipe out the commands list to avoid issues if additional
+ # commands are executed later
+ self._commands = list()
+
+ return responses
+
+class Command(object):
+
+ def __init__(self, command, output=None, prompt=None, is_reboot=False,
+ response=None, delay=0):
+
+ self.command = command
+ self.output = output
+
+ self.prompt = prompt
+ self.response = response
+
+ self.is_reboot = is_reboot
+ self.delay = delay
+
+ def __str__(self):
+ return self.command
+
+class CommandRunner(object):
+
+ def __init__(self, module):
+ self.module = module
+
+ self.items = list()
+ self.conditionals = set()
+
+ self.commands = list()
+
+ self.retries = 10
+ self.interval = 1
+
+ self.match = 'all'
+
+ self._cache = dict()
+ self._default_output = module.connection.default_output
+
+
+ def add_command(self, command, output=None, prompt=None, response=None):
+ if command in [str(c) for c in self.commands]:
+ raise AddCommandError('duplicated command detected', command=command)
+ cmd = self.module.cli.to_command(command, output=output, prompt=prompt,
+ response=response)
+ self.commands.append(cmd)
+
+ def get_command(self, command, output=None):
+ output = output or self._default_output
+ try:
+ cmdobj = self._cache[(command, output)]
+ return cmdobj.response
+ except KeyError:
+ for cmd in self.commands:
+ if str(cmd) == command and cmd.output == output:
+ self._cache[(command, output)] = cmd
+ return cmd.response
+ raise ValueError("command '%s' not found" % command)
+
+ def get_responses(self):
+ return [cmd.response for cmd in self.commands]
+
+ def add_conditional(self, condition):
+ self.conditionals.add(Conditional(condition))
+
+ def run(self):
+ while self.retries > 0:
+ self.module.cli.add_commands(self.commands)
+ responses = self.module.cli.run_commands()
+
+ for item in list(self.conditionals):
+ if item(responses):
+ if self.match == 'any':
+ return item
+ self.conditionals.remove(item)
+
+ if not self.conditionals:
+ break
+
+ time.sleep(self.interval)
+ self.retries -= 1
+ else:
+ failed_conditions = [item.raw for item in self.conditionals]
+ errmsg = 'One or more conditional statements have not be satisfied'
+ raise FailedConditionsError(errmsg, failed_conditions)
+
class Conditional(object):
"""Used in command modules to evaluate waitfor conditions
"""
@@ -154,62 +297,3 @@ class Conditional(object):
match = re.search(value, self.value, re.M)
return match is not None
-
-class FailedConditionsError(Exception):
-
- def __init__(self, msg, failed_conditions):
- super(FailedConditionsError, self).__init__(msg)
- self.failed_conditions = failed_conditions
-
-class CommandRunner(object):
-
- def __init__(self, module):
- self.module = module
-
- self.items = list()
- self.conditionals = set()
-
- self.retries = 10
- self.interval = 1
-
- self._cache = dict()
-
- def add_command(self, command, output=None):
- self.module.cli.add_commands(command, output=output)
-
- def get_command(self, command):
- try:
- cmdobj = self._cache[command]
- return cmdobj.response
- except KeyError:
- for cmd in self.module.cli.commands:
- if str(cmd) == command:
- self._cache[command] = cmd
- return cmd.response
- raise ValueError("command '%s' not found" % command)
-
-
- def add_conditional(self, condition):
- self.conditionals.add(Conditional(condition))
-
- def run_commands(self):
- responses = self.module.cli.run_commands()
- self.items = responses
-
- def run(self):
- while self.retries > 0:
- self.run_commands()
-
- for item in list(self.conditionals):
- if item(self.items):
- self.conditionals.remove(item)
-
- if not self.conditionals:
- break
-
- time.sleep(self.interval)
- self.retries -= 1
- else:
- failed_conditions = [item.raw for item in self.conditionals]
- raise FailedConditionsError('timeout waiting for value', failed_conditions)
-