def send(self, command, prompt=None, answer=None, newline=True, sendonly=False, prompt_retry_check=False, check_all=False): ''' Sends the command to the device in the opened shell ''' if check_all: prompt_len = len(to_list(prompt)) answer_len = len(to_list(answer)) if prompt_len != answer_len: raise AnsibleConnectionFailure( "Number of prompts (%s) is not same as that of answers (%s)" % (prompt_len, answer_len)) try: cmd = b'%s\r' % command self._history.append(cmd) self._ssh_shell.sendall(cmd) self._log_messages('send command: %s' % cmd) if sendonly: return response = self.receive(command, prompt, answer, newline, prompt_retry_check, check_all) return to_text(response, errors='surrogate_then_replace') except (socket.timeout, AttributeError): self.queue_message('error', traceback.format_exc()) raise AnsibleConnectionFailure( "timeout value %s seconds reached while trying to send command: %s" % (self._ssh_shell.gettimeout(), command.strip()))
def test_to_list(): for scalar in ('string', 1, True, False, None): assert isinstance(to_list(scalar), list) for container in ([1, 2, 3], {'one': 1}): assert isinstance(to_list(container), list) test_list = [1, 2, 3] assert id(test_list) != id(to_list(test_list))
def run_queue(queue, output): try: response = to_list( self._connection.send_request(queue, output=output)) except ConnectionError as exc: if check_rc: raise return to_list(to_text(exc)) if output == 'json': response = [json.loads(item) for item in response] return response
def run_commands(self, commands=None, check_rc=True): if commands is None: raise ValueError("'commands' value is required") responses = list() for cmd in to_list(commands): if not isinstance(cmd, Mapping): cmd = {'command': cmd} output = cmd.pop('output', None) if output: cmd['command'] = self._get_command_with_output(cmd['command'], output) try: out = self.send_command(**cmd) except AnsibleConnectionFailure as e: if check_rc: raise out = getattr(e, 'err', e) out = to_text(out, errors='surrogate_or_strict') if out is not None: try: out = json.loads(out) except ValueError: out = out.strip() responses.append(out) return responses
def send_request(self, data, **message_kwargs): data = to_list(data) become = self._become if become: self.connection.queue_message('vvvv', 'firing event: on_become') data.insert(0, {"cmd": "enable", "input": self._become_pass}) output = message_kwargs.get('output', 'text') request = request_builder(data, output) headers = {'Content-Type': 'application/json-rpc'} response, response_data = self.connection.send('/command-api', request, headers=headers, method='POST') try: response_data = json.loads(to_text(response_data.getvalue())) except ValueError: raise ConnectionError( 'Response was not valid JSON, got {0}'.format( to_text(response_data.getvalue()))) results = handle_response(response_data) if become: results = results[1:] if len(results) == 1: results = results[0] return results
def send_request(self, data, **message_kwargs): output = None queue = list() responses = list() for item in to_list(data): cmd_output = message_kwargs.get('output', 'text') if isinstance(item, dict): command = item['command'] if 'output' in item: cmd_output = item['output'] else: command = item # Emulate '| json' from CLI if command.endswith('| json'): command = command.rsplit('|', 1)[0] cmd_output = 'json' if output and output != cmd_output: responses.extend(self._run_queue(queue, output)) queue = list() output = cmd_output queue.append(command) if queue: responses.extend(self._run_queue(queue, output)) if len(responses) == 1: return responses[0] return responses
def execute_module(self): """ Execute the module :rtype: A dictionary :returns: The result from module execution """ result = {'changed': False} existing_interfaces_facts = self.get_interfaces_facts() config_xmls = self.set_config(existing_interfaces_facts) with locked_config(self._module): for config_xml in to_list(config_xmls): diff = load_config(self._module, config_xml, []) commit = not self._module.check_mode if diff: if commit: commit_configuration(self._module) else: discard_changes(self._module) result['changed'] = True if self._module._diff: result['diff'] = {'prepared': diff} result['commands'] = config_xmls changed_interfaces_facts = self.get_interfaces_facts() result['before'] = existing_interfaces_facts if result['changed']: result['after'] = changed_interfaces_facts return result
def run_commands(self, commands=None, check_rc=True): if commands is None: raise ValueError("'commands' value is required") responses = list() for cmd in to_list(commands): if not isinstance(cmd, Mapping): cmd = {'command': cmd} output = cmd.pop('output', None) if output: raise ValueError( "'output' value %s is not supported for run_commands" % output) try: out = self.send_command(**cmd) except AnsibleConnectionFailure as e: if check_rc: raise out = getattr(e, 'err', e) responses.append(out) return responses
def render(self, config=None, nbr_list=None): commands = list() safe_list = list() if not nbr_list: nbr_list = self.get_value('config.neighbors') for item in nbr_list: neighbor_commands = list() context = 'neighbor %s' % item['neighbor'] cmd = '%s remote-as %s' % (context, item['remote_as']) if not config or cmd not in config: neighbor_commands.append(cmd) for key, value in iteritems(item): if value is not None: meth = getattr(self, '_render_%s' % key, None) if meth: resp = meth(item, config) if resp: neighbor_commands.extend(to_list(resp)) commands.extend(neighbor_commands) safe_list.append(context) if self.params['operation'] == 'replace': if config and safe_list: commands.extend(self._negate_config(config, safe_list)) return commands
def set_config(self, existing_bfd_interfaces_facts, platform): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ if re.search('N[56]K', platform): # Some platforms do not support the 'bfd' interface keyword; # remove the 'bfd' key from each want/have interface. orig_want = self._module.params['config'] want = [] for w in orig_want: del w['bfd'] want.append(w) orig_have = existing_bfd_interfaces_facts have = [] for h in orig_have: del h['bfd'] have.append(h) else: want = self._module.params['config'] have = existing_bfd_interfaces_facts resp = self.set_state(want, have) return to_list(resp)
def run_commands(self, commands, check_rc=True): """Run list of commands on remote device and return results """ output = None queue = list() responses = list() def _send(commands, output): return self.send_request(commands, output, check_status=check_rc) for item in to_list(commands): if is_json(item['command']): item['command'] = str(item['command']).rsplit('|', 1)[0] item['output'] = 'json' if all((output == 'json', item['output'] == 'text')) or all((output == 'text', item['output'] == 'json')): responses.extend(_send(queue, output)) queue = list() output = item['output'] or 'json' queue.append(item['command']) if queue: responses.extend(_send(queue, output)) return responses
def render(self, config=None): commands = list() safe_list = list() router_context = 'router bgp %s' % self.get_value('config.bgp_as') context_config = None for item in self.get_value('config.address_family'): context = 'address-family %s %s' % (item['afi'], item['safi']) context_commands = list() if config: context_path = [router_context, context] context_config = self.get_config_context(config, context_path, indent=1) for key, value in iteritems(item): if value is not None: meth = getattr(self, '_render_%s' % key, None) if meth: resp = meth(item, context_config) if resp: context_commands.extend(to_list(resp)) if context_commands: commands.append(context) commands.extend(context_commands) commands.append('exit') safe_list.append(context) if config: resp = self._negate_config(config, safe_list) commands.extend(resp) return commands
def edit_config(self, candidate=None, commit=True, replace=None, comment=None): resp = {} operations = self.get_device_operations() self.check_edit_config_capability(operations, candidate, commit, replace, comment) results = [] requests = [] if commit: self.send_command('configure terminal') for line in to_list(candidate): if not isinstance(line, Mapping): line = {'command': line} cmd = line['command'] if cmd != 'end' and cmd[0] != '!': results.append(self.send_command(**line)) requests.append(cmd) self.send_command('end') else: raise ValueError('check mode is not supported') resp['request'] = requests resp['response'] = results return resp
def edit_config(self, candidate=None, commit=True, replace=None, comment=None): operations = self.get_device_operations() self.check_edit_config_capability(operations, candidate, commit, replace, comment) if (commit is False) and (not self.supports_sessions()): raise ValueError('check mode is not supported without configuration session') resp = {} session = None if self.supports_sessions(): session = 'ansible_%s' % int(time.time()) resp.update({'session': session}) self.send_command('configure session %s' % session) if replace: self.send_command('rollback clean-config') else: self.send_command('configure') results = [] requests = [] multiline = False for line in to_list(candidate): if not isinstance(line, Mapping): line = {'command': line} cmd = line['command'] if cmd == 'end': continue elif cmd.startswith('banner') or multiline: multiline = True elif cmd == 'EOF' and multiline: multiline = False if multiline: line['sendonly'] = True if cmd != 'end' and cmd[0] != '!': try: results.append(self.send_command(**line)) requests.append(cmd) except AnsibleConnectionFailure as e: self.discard_changes(session) raise AnsibleConnectionFailure(e.message) resp['request'] = requests resp['response'] = results if self.supports_sessions(): out = self.send_command('show session-config diffs') if out: resp['diff'] = out.strip() if commit: self.commit() else: self.discard_changes(session) else: self.send_command('end') return resp
def get_section(self, config, section): if config is not None: netcfg = NetworkConfig(indent=1, contents=config) try: config = netcfg.get_block_config(to_list(section)) except ValueError: config = None return config
def get_config_context(self, config, path, indent=1): if config is not None: netcfg = NetworkConfig(indent=indent, contents=config) try: config = netcfg.get_block_config(to_list(path)) except ValueError: config = None return config
def load_config(module, config, commit=False): conn = get_connection(module) try: resp = conn.edit_config(to_list(config) + ['top'], commit) except ConnectionError as exc: module.fail_json(msg=to_text(exc, errors='surrogate_then_replace')) diff = resp.get('diff', '') return to_text(diff, errors='surrogate_then_replace').strip()
def execute_show_commands(module, commands, output='text'): cmds = [] for command in to_list(commands): cmd = {'command': command, 'output': output, } cmds.append(cmd) body = run_commands(module, cmds) return body
def parse_roles(data): configured_roles = None if 'TABLE_role' in data: configured_roles = data.get('TABLE_role')['ROW_role'] roles = list() if configured_roles: for item in to_list(configured_roles): roles.append(item['role']) return roles
def set_config(self, existing_l3_interfaces_facts): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ want = self._module.params['config'] have = existing_l3_interfaces_facts resp = self.set_state(want, have) return to_list(resp)
def set_config(self, existing_tms_global_facts): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ config = self._module.params['config'] want = dict((k, v) for k, v in config.items() if v is not None) have = existing_tms_global_facts resp = self.set_state(want, have) return to_list(resp)
def set_config(self, existing_lldp_global_facts): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ want = self._module.params['config'] if not want and self._module.params['state'] == 'deleted': want = {} have = existing_lldp_global_facts resp = self.set_state(want, have) return to_list(resp)
def wrapper(cls): _provider_lock.acquire() try: if network_os not in _registered_providers: _registered_providers[network_os] = {} for ct in cls.supported_connections: if ct not in _registered_providers[network_os]: _registered_providers[network_os][ct] = {} for item in to_list(module_name): for entry in itervalues(_registered_providers[network_os]): entry[item] = cls finally: _provider_lock.release() return cls
def render(self, config=None): commands = list() existing_as = None if config: match = re.search(r'router bgp (\d+)', config, re.M) if match: existing_as = match.group(1) operation = self.params['operation'] context = None if self.params['config']: context = 'router bgp %s' % self.get_value('config.bgp_as') if operation == 'delete': if existing_as: commands.append('no router bgp %s' % existing_as) elif context: commands.append('no %s' % context) else: self._validate_input(config) if operation == 'replace': if existing_as and int(existing_as) != self.get_value( 'config.bgp_as'): commands.append('no router bgp %s' % existing_as) config = None elif operation == 'override': if existing_as: commands.append('no router bgp %s' % existing_as) config = None context_commands = list() for key, value in iteritems(self.get_value('config')): if value is not None: meth = getattr(self, '_render_%s' % key, None) if meth: resp = meth(config) if resp: context_commands.extend(to_list(resp)) if context and context_commands: commands.append(context) commands.extend(context_commands) commands.append('exit') return commands
def map_config_to_obj(module): out = run_commands(module, ['show user-account | json']) data = out[0] objects = list() for item in to_list(data['TABLE_template']['ROW_template']): objects.append({ 'name': item['usr_name'], 'configured_password': parse_password(item), 'sshkey': item.get('sshkey_info'), 'roles': parse_roles(item), 'state': 'present' }) return objects
def set_config(self, existing_vlans_facts): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ config = self._module.params.get('config') want = [] if config: for w in config: want.append(remove_empties(w)) have = existing_vlans_facts resp = self.set_state(want, have) return to_list(resp)
def get_config(self, source='running', format='text', flags=None): options_values = self.get_option_values() if format not in options_values['format']: raise ValueError("'format' value %s is invalid. Valid values are %s" % (format, ','.join(options_values['format']))) lookup = {'running': 'running-config', 'startup': 'startup-config'} if source not in lookup: raise ValueError("fetching configuration from %s is not supported" % source) cmd = 'show %s ' % lookup[source] if format and format != 'text': cmd += '| %s ' % format cmd += ' '.join(to_list(flags)) cmd = cmd.strip() return self.send_command(cmd)
def edit_config(self, candidate=None, commit=True, replace=None, comment=None): resp = list() self.check_edit_config_capability(candidate, commit, replace, comment) if replace: candidate = 'config replace {0}'.format(replace) responses = self._connection.send_request(candidate, output='config') for response in to_list(responses): if response != '{}': resp.append(response) if not resp: resp = [''] return resp
def edit_config(self, candidate=None, commit=True, replace=None, comment=None): resp = {} operations = self.get_device_operations() self.check_edit_config_capability(operations, candidate, commit, replace, comment) results = [] requests = [] self.send_command('configure') for cmd in to_list(candidate): if not isinstance(cmd, Mapping): cmd = {'command': cmd} results.append(self.send_command(**cmd)) requests.append(cmd['command']) out = self.get('compare') out = to_text(out, errors='surrogate_or_strict') diff_config = out if not out.startswith('No changes') else None if diff_config: if commit: try: self.commit(comment) except AnsibleConnectionFailure as e: msg = 'commit failed: %s' % e.message self.discard_changes() raise AnsibleConnectionFailure(msg) else: self.send_command('exit') else: self.discard_changes() else: self.send_command('exit') if to_text(self._connection.get_prompt(), errors='surrogate_or_strict').strip().endswith('#'): self.discard_changes() if diff_config: resp['diff'] = diff_config resp['response'] = results resp['request'] = requests return resp
def set_config(self, existing_hsrp_interfaces_facts): """ Collect the configuration from the args passed to the module, collect the current configuration (as a dict from facts) :rtype: A list :returns: the commands necessary to migrate the current configuration to the desired configuration """ config = self._module.params['config'] want = [] if config: for w in config: w.update({'name': normalize_interface(w['name'])}) want.append(w) have = existing_hsrp_interfaces_facts resp = self.set_state(want, have) return to_list(resp)