def run(self, args, variables=None, vm=None, create=True, no_symbols=False, default=UNDEFINED): ret = [] cmd = ['qvm-pass'] if vm is not None: cmd += ['-d', vm] if create: cmd += ['get-or-generate'] if no_symbols: cmd += ["-n"] else: cmd += ['get'] cmd += ['--', args[0]] display.vvvv(u"Password lookup using command %s" % cmd) try: ret = subprocess.check_output(cmd)[:-1] except subprocess.CalledProcessError as e: if e.returncode == 8: if create or default is UNDEFINED: raise AnsibleError("qubes-pass could not locate password entry %s in store" % args[0]) return [default] else: raise AnsibleError("qubes-pass lookup failed: %s" % e) return [ret]
def _start_connection(self): ''' Starts the persistent connection ''' master, slave = pty.openpty() python = sys.executable def find_file_in_path(filename): # Check $PATH first, followed by same directory as sys.argv[0] paths = os.environ['PATH'].split(os.pathsep) + [os.path.dirname(sys.argv[0])] for dirname in paths: fullpath = os.path.join(dirname, filename) if os.path.isfile(fullpath): return fullpath raise AnsibleError("Unable to find location of '%s'" % filename) p = subprocess.Popen( [python, find_file_in_path('ansible-connection'), to_text(os.getppid())], stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) stdin = os.fdopen(master, 'wb', 0) os.close(slave) # Need to force a protocol that is compatible with both py2 and py3. # That would be protocol=2 or less. # Also need to force a protocol that excludes certain control chars as # stdin in this case is a pty and control chars will cause problems. # that means only protocol=0 will work. src = cPickle.dumps(self._play_context.serialize(), protocol=0) stdin.write(src) stdin.write(b'\n#END_INIT#\n') stdin.flush() (stdout, stderr) = p.communicate() stdin.close() if p.returncode == 0: result = json.loads(to_text(stdout, errors='surrogate_then_replace')) else: try: result = json.loads(to_text(stderr, errors='surrogate_then_replace')) except getattr(json.decoder, 'JSONDecodeError', ValueError): # JSONDecodeError only available on Python 3.5+ result = {'error': to_text(stderr, errors='surrogate_then_replace')} if 'messages' in result: for msg in result.get('messages'): display.vvvv('%s' % msg, host=self._play_context.remote_addr) if 'error' in result: if self._play_context.verbosity > 2: if result.get('exception'): msg = "The full traceback is:\n" + result['exception'] display.display(msg, color=C.COLOR_ERROR) raise AnsibleError(result['error']) return result['socket_path']
def _connect(self): ''' activates the connection object ''' if not self._connected: wrong_user = False tries = 3 self.conn = socket.socket() self.conn.settimeout(C.ACCELERATE_CONNECT_TIMEOUT) display.vvvv("attempting connection to %s via the accelerated port %d" % (self._play_context.remote_addr, self._play_context.accelerate_port), host=self._play_context.remote_addr) while tries > 0: try: self.conn.connect((self._play_context.remote_addr,self._play_context.accelerate_port)) break except socket.error: display.vvvv("connection to %s failed, retrying..." % self._play_context.remote_addr, host=self._play_context.remote_addr) time.sleep(0.1) tries -= 1 if tries == 0: display.vvv("Could not connect via the accelerated connection, exceeded # of tries", host=self._play_context.remote_addr) raise AnsibleConnectionFailure("Failed to connect to %s on the accelerated port %s" % (self._play_context.remote_addr, self._play_context.accelerate_port)) elif wrong_user: display.vvv("Restarting daemon with a different remote_user", host=self._play_context.remote_addr) raise AnsibleError("The accelerated daemon was started on the remote with a different user") self.conn.settimeout(C.ACCELERATE_TIMEOUT) if not self.validate_user(): # the accelerated daemon was started with a # different remote_user. The above command # should have caused the accelerate daemon to # shutdown, so we'll reconnect. wrong_user = True self._connected = True return self
def run(self, terms, variables=None, **kwargs): validate_certs = kwargs.get('validate_certs', True) split_lines = kwargs.get('split_lines', True) use_proxy = kwargs.get('use_proxy', True) ret = [] for term in terms: display.vvvv("url lookup connecting to %s" % term) try: response = open_url(term, validate_certs=validate_certs, use_proxy=use_proxy) except HTTPError as e: raise AnsibleError("Received HTTP error for %s : %s" % (term, str(e))) except URLError as e: raise AnsibleError("Failed lookup url for %s : %s" % (term, str(e))) except SSLValidationError as e: raise AnsibleError("Error validating the server's certificate for %s: %s" % (term, str(e))) except ConnectionError as e: raise AnsibleError("Error connecting to %s: %s" % (term, str(e))) if split_lines: for line in response.read().splitlines(): ret.append(to_text(line)) else: ret.append(to_text(response.read())) return ret
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection ) provider = load_provider(sros_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'sros' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider['username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return {'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} task_vars['ansible_socket'] = socket_path result = super(ActionModule, self).run(tmp, task_vars) return result
def run(self, tmp=None, task_vars=None): display.v("a log") display.vv("Kind of verbose") display.vvv("Verbose") display.vvvv("Lookout!") display.verbose("Super custom verbosity", caplevel=6) return {'msg': 'done'}
def run(self, tmp=None, task_vars=None): del tmp # tmp no longer has any effect if self._play_context.connection == 'local': provider = load_provider(asa_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'asa' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider['username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) pc.become = provider['authorize'] or False pc.become_pass = provider['auth_pass'] pc.become_method = 'enable' display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return {'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} task_vars['ansible_socket'] = socket_path result = super(ActionModule, self).run(task_vars=task_vars) return result
def run(self, terms, variables, **kwargs): convert_data_p = kwargs.get('convert_data', True) ret = [] for term in terms: display.debug("File lookup term: %s" % term) lookupfile = self.find_file_in_search_path(variables, 'templates', term) display.vvvv("File lookup using %s as file" % lookupfile) if lookupfile: with open(to_bytes(lookupfile, errors='surrogate_or_strict'), 'rb') as f: template_data = to_text(f.read(), errors='surrogate_or_strict') # set jinja2 internal search path for includes if 'ansible_search_path' in variables: searchpath = variables['ansible_search_path'] else: searchpath = [self._loader._basedir, os.path.dirname(lookupfile)] self._templar.environment.loader.searchpath = searchpath # do the templating res = self._templar.template(template_data, preserve_trailing_newlines=True,convert_data=convert_data_p) ret.append(res) else: raise AnsibleError("the template file %s could not be found for the lookup" % term) return ret
def _start_connection(self, play_context): display.vvv('using connection plugin %s' % play_context.connection, play_context.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', play_context, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, play_context.remote_addr) if not socket_path: return {'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} # make sure we are in the right cli context which should be # enable mode and not config module rc, out, err = connection.exec_command('prompt()') if str(out).strip().endswith(')#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) connection.exec_command('exit') if self._play_context.become_method == 'enable': self._play_context.become = False self._play_context.become_method = None return socket_path
def run(self, terms, variables=None, **kwargs): # lookups in general are expected to both take a list as input and output a list # this is done so they work with the looping construct `with_`. # Only the gods know why you would want to look through several viya licenses files, but conventions are conventions for a reason... so here we are. ret = [] for term in terms: display.debug("License lookup term: %s" % term) # Find the file in the expected search path, using a class method # that implements the 'expected' search path for Ansible plugins. lookupfile = self.find_file_in_search_path(variables, 'files', term) # Don't use print or your own logging, the display class # takes care of it in a unified way. display.vvvv(u"Sas License lookup using %s as file" % lookupfile) try: if lookupfile: sas_license = SasLicense(lookupfile) # contents, show_data = self._loader._get_file_contents(lookupfile) ret.append(sas_license.get_ansible_dict()) else: # Always use ansible error classes to throw 'final' exceptions, # so the Ansible engine will know how to deal with them. # The Parser error indicates invalid options passed raise AnsibleParserError() except AnsibleParserError: raise AnsibleError("could not locate file in lookup: %s" % term) return ret
def run(self, terms, variables, **kwargs): convert_data_p = kwargs.get('convert_data', True) basedir = self.get_basedir(variables) ret = [] for term in terms: display.debug("File lookup term: %s" % term) lookupfile = self._loader.path_dwim_relative(basedir, 'templates', term) display.vvvv("File lookup using %s as file" % lookupfile) if lookupfile and os.path.exists(lookupfile): with open(lookupfile, 'r') as f: template_data = to_unicode(f.read()) searchpath = [self._loader._basedir, os.path.dirname(lookupfile)] if 'role_path' in variables: searchpath.insert(1, C.DEFAULT_ROLES_PATH) searchpath.insert(1, variables['role_path']) self._templar.environment.loader.searchpath = searchpath res = self._templar.template(template_data, preserve_trailing_newlines=True,convert_data=convert_data_p) ret.append(res) else: raise AnsibleError("the template file %s could not be found for the lookup" % term) return ret
def add_host(self, host, group=None, port=None): ''' adds a host to inventory and possibly a group if not there already ''' g = None if group: if group in self.groups: g = self.groups[group] else: raise AnsibleError("Could not find group %s in inventory" % group) if host not in self.hosts: h = Host(host, port) self.hosts[host] = h if self.current_source: # set to 'first source' in which host was encountered self.set_variable(host, 'inventory_file', os.path.basename(self.current_source)) self.set_variable(host, 'inventory_dir', basedir(self.current_source)) else: self.set_variable(host, 'inventory_file', None) self.set_variable(host, 'inventory_dir', None) display.debug("Added host %s to inventory" % (host)) # set default localhost from inventory to avoid creating an implicit one. Last localhost defined 'wins'. if host in C.LOCALHOST: if self.localhost is None: self.localhost = self.hosts[host] display.vvvv("Set default localhost to %s" % h) else: display.warning("A duplicate localhost-like entry was found (%s). First found localhost was %s" % (h, self.localhost.name)) else: h = self.hosts[host] if g: g.add_host(h) self._groups_dict_cache = {} display.debug("Added host %s to group %s" % (host, group))
def run(self, terms, variables=None, **kwargs): ret = [] basedir = self.get_basedir(variables) for term in terms: display.debug("File lookup term: %s" % term) # Special handling of the file lookup, used primarily when the # lookup is done from a role. If the file isn't found in the # basedir of the current file, use dwim_relative to look in the # role/files/ directory, and finally the playbook directory # itself (which will be relative to the current working dir) lookupfile = self._loader.path_dwim_relative(basedir, 'files', term) display.vvvv("File lookup using %s as file" % lookupfile) try: if lookupfile: contents, show_data = self._loader._get_file_contents(lookupfile) ret.append(contents.rstrip()) else: raise AnsibleParserError() except AnsibleParserError: raise AnsibleError("could not locate file in lookup: %s" % term) return ret
def run(self, terms, variables=None, **kwargs): ret = [] for term in terms: display.debug("File lookup term: %s" % term) # Find the file in the expected search path lookupfile = self.find_file_in_search_path(variables, 'files', term) display.vvvv(u"File lookup using %s as file" % lookupfile) try: if lookupfile: b_contents, show_data = self._loader._get_file_contents(lookupfile) contents = to_text(b_contents, errors='surrogate_or_strict') if kwargs.get('lstrip', False): contents = contents.lstrip() if kwargs.get('rstrip', True): contents = contents.rstrip() ret.append(contents) else: raise AnsibleParserError() except AnsibleParserError: raise AnsibleError("could not locate file in lookup: %s" % term) return ret
def fetch_file(self, in_path, out_path): '''Fetch a file from VM to local.''' super(Connection, self).fetch_file(in_path, out_path) display.vvvv("FETCH %s to %s" % (in_path, out_path), host=self._play_context.remote_addr) in_path = _prefix_login_path(in_path) out_file = open(out_path, "wb") try: payload = 'fetch(%r, %r)\n' % (in_path, BUFSIZE) self._transport.stdin.write(payload) self._transport.stdin.flush() while True: chunk_len = self._transport.stdout.readline(16) try: chunk_len = int(chunk_len) except Exception: if chunk_len == "N\n": exc = decode_exception(self._transport.stdin) raise exc else: self._abort_transport() raise errors.AnsibleError("chunk size from remote end is unexpected: %r" % chunk_len) if chunk_len > BUFSIZE or chunk_len < 0: raise errors.AnsibleError("chunk size from remote end is invalid: %r" % chunk_len) if chunk_len == 0: break chunk = self._transport.stdout.read(chunk_len) if len(chunk) != chunk_len: raise errors.AnsibleError("stderr size from remote end does not match actual stderr length: %s != %s" % (chunk_len, len(chunk))) out_file.write(chunk) except Exception: self._abort_transport() raise
def reset(self): ''' Reset the connection ''' if self._socket_path: display.vvvv('resetting persistent connection for socket_path %s' % self._socket_path, host=self._play_context.remote_addr) self.close() display.vvvv('reset call on connection instance', host=self._play_context.remote_addr)
def _winrm_connect(self): ''' Establish a WinRM connection over HTTP/HTTPS. ''' display.vvv("ESTABLISH WINRM CONNECTION FOR USER: %s on PORT %s TO %s" % (self._winrm_user, self._winrm_port, self._winrm_host), host=self._winrm_host) winrm_host = self._winrm_host if HAS_IPADDRESS: display.vvvv("checking if winrm_host %s is an IPv6 address" % winrm_host) try: ipaddress.IPv6Address(winrm_host) except ipaddress.AddressValueError: pass else: winrm_host = "[%s]" % winrm_host netloc = '%s:%d' % (winrm_host, self._winrm_port) endpoint = urlunsplit((self._winrm_scheme, netloc, self._winrm_path, '', '')) errors = [] for transport in self._winrm_transport: if transport == 'kerberos': if not HAVE_KERBEROS: errors.append('kerberos: the python kerberos library is not installed') continue if self._kerb_managed: self._kerb_auth(self._winrm_user, self._winrm_pass) display.vvvvv('WINRM CONNECT: transport=%s endpoint=%s' % (transport, endpoint), host=self._winrm_host) try: winrm_kwargs = self._winrm_kwargs.copy() if self._winrm_connection_timeout: winrm_kwargs['operation_timeout_sec'] = self._winrm_connection_timeout winrm_kwargs['read_timeout_sec'] = self._winrm_connection_timeout + 1 protocol = Protocol(endpoint, transport=transport, **winrm_kwargs) # open the shell from connect so we know we're able to talk to the server if not self.shell_id: self.shell_id = protocol.open_shell(codepage=65001) # UTF-8 display.vvvvv('WINRM OPEN SHELL: %s' % self.shell_id, host=self._winrm_host) return protocol except Exception as e: err_msg = to_text(e).strip() if re.search(to_text(r'Operation\s+?timed\s+?out'), err_msg, re.I): raise AnsibleError('the connection attempt timed out') m = re.search(to_text(r'Code\s+?(\d{3})'), err_msg) if m: code = int(m.groups()[0]) if code == 401: err_msg = 'the specified credentials were rejected by the server' elif code == 411: return protocol errors.append(u'%s: %s' % (transport, err_msg)) display.vvvvv(u'WINRM CONNECTION ERROR: %s\n%s' % (err_msg, to_text(traceback.format_exc())), host=self._winrm_host) if errors: raise AnsibleConnectionFailure(', '.join(map(to_native, errors))) else: raise AnsibleError('No transport found for WinRM connection')
def run(self, terms, variables=None, **kwargs): for term in terms: display.debug("Fileexists lookup term: %s" % term) try: lookupfile = self.find_file_in_search_path(variables, 'files', term) display.vvvv(u"Fileexists lookup using %s as file" % lookupfile) except AnsibleError: return False return True
def _fetch_conjur_token(conjur_url, account, username, api_key): conjur_url = '{0}/authn/{1}/{2}/authenticate'.format(conjur_url, account, username) display.vvvv('Authentication request to Conjur at: {0}, with user: {1}'.format(conjur_url, username)) response = open_url(conjur_url, data=api_key, method='POST') code = response.getcode() if code != 200: raise AnsibleError('Failed to authenticate as \'{0}\' (got {1} response)' .format(username, code)) return response.read()
def _kerb_auth(self, principal, password): if password is None: password = "" self._kerb_ccache = tempfile.NamedTemporaryFile() display.vvvvv("creating Kerberos CC at %s" % self._kerb_ccache.name) krb5ccname = "FILE:%s" % self._kerb_ccache.name os.environ["KRB5CCNAME"] = krb5ccname krb5env = dict(KRB5CCNAME=krb5ccname) # stores various flags to call with kinit, we currently only use this # to set -f so we can get a forward-able ticket (cred delegation) kinit_flags = [] if boolean(self.get_option('_extras').get('ansible_winrm_kerberos_delegation', False)): kinit_flags.append('-f') kinit_cmdline = [self._kinit_cmd] kinit_cmdline.extend(kinit_flags) kinit_cmdline.append(principal) # pexpect runs the process in its own pty so it can correctly send # the password as input even on MacOS which blocks subprocess from # doing so. Unfortunately it is not available on the built in Python # so we can only use it if someone has installed it if HAS_PEXPECT: kinit_cmdline = " ".join(kinit_cmdline) password = to_text(password, encoding='utf-8', errors='surrogate_or_strict') display.vvvv("calling kinit with pexpect for principal %s" % principal) events = { ".*:": password + "\n" } # technically this is the stdout but to match subprocess we will # call it stderr stderr, rc = pexpect.run(kinit_cmdline, withexitstatus=True, events=events, env=krb5env, timeout=60) else: password = to_bytes(password, encoding='utf-8', errors='surrogate_or_strict') display.vvvv("calling kinit with subprocess for principal %s" % principal) p = subprocess.Popen(kinit_cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=krb5env) stdout, stderr = p.communicate(password + b'\n') rc = p.returncode != 0 if rc != 0: raise AnsibleConnectionFailure("Kerberos auth failure: %s" % to_native(stderr.strip())) display.vvvvv("kinit succeeded for principal %s" % principal)
def run(self, tmp=None, task_vars=None): del tmp # tmp no longer has any effect socket_path = None if self._play_context.connection == 'network_cli': provider = self._task.args.get('provider', {}) if any(provider.values()): display.warning('provider is unnecessary when using network_cli and will be ignored') del self._task.args['provider'] elif self._play_context.connection == 'local': provider = load_provider(ios_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'ios' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider['username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) pc.become = provider['authorize'] or False if pc.become: pc.become_method = 'enable' pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return {'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} task_vars['ansible_socket'] = socket_path else: return {'failed': True, 'msg': 'Connection type %s is not valid for this module' % self._play_context.connection} # make sure we are in the right cli context which should be # enable mode and not config module if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() while to_text(out, errors='surrogate_then_replace').strip().endswith(')#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('exit') out = conn.get_prompt() result = super(ActionModule, self).run(task_vars=task_vars) return result
def run(self, tmp=None, task_vars=None): del tmp # tmp no longer has any effect if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection ) provider = load_provider(ironware_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'ironware' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider['username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) pc.become = provider['authorize'] or False if pc.become: pc.become_method = 'enable' pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return {'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} # make sure we are in the right cli context which should be # enable mode and not config module conn = Connection(socket_path) out = conn.get_prompt() if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'): display.vvvv('wrong context, sending end to device', self._play_context.remote_addr) conn.send_command('end') task_vars['ansible_socket'] = socket_path if self._play_context.become_method == 'enable': self._play_context.become = False self._play_context.become_method = None result = super(ActionModule, self).run(task_vars=task_vars) return result
def run(self): """Returns the path of the persistent connection socket. Attempts to ensure (within playcontext.timeout seconds) that the socket path exists. If the path exists (or the timeout has expired), returns the socket path. """ display.vvvv('starting connection from persistent connection plugin', host=self._play_context.remote_addr) socket_path = self._start_connection() display.vvvv('local domain socket path is %s' % socket_path, host=self._play_context.remote_addr) setattr(self, '_socket_path', socket_path) return socket_path
def exec_command(self, cmd, in_data=None, sudoable=False): '''Run a command on the VM.''' super(Connection, self).exec_command(cmd, in_data=in_data, sudoable=sudoable) if isinstance(cmd, basestring): cmd = shlex.split(cmd) display.vvvv("EXEC %s" % cmd, host=self._play_context.remote_addr) try: payload = 'popen(%r, %r)\n' % (cmd, in_data) self._transport.stdin.write(payload) self._transport.stdin.flush() yesno = self._transport.stdout.readline(2) except Exception: self._abort_transport() raise if yesno == "Y\n": try: retcode = self._transport.stdout.readline(16) try: retcode = int(retcode) except Exception: raise errors.AnsibleError("return code from remote end is unexpected: %r" % retcode) if retcode > 65536 or retcode < -65535: raise errors.AnsibleError("return code from remote end is outside the range: %r" % retcode) stdout_len = self._transport.stdout.readline(16) try: stdout_len = int(stdout_len) except Exception: raise errors.AnsibleError("stdout size from remote end is unexpected: %r" % stdout_len) if stdout_len > 1024*1024*1024 or stdout_len < 0: raise errors.AnsibleError("stdout size from remote end is invalid: %r" % stdout_len) stdout = self._transport.stdout.read(stdout_len) if stdout_len != 0 else '' if len(stdout) != stdout_len: raise errors.AnsibleError("stdout size from remote end does not match actual stdout length: %s != %s" % (stdout_len, len(stdout))) stderr_len = self._transport.stdout.readline(16) try: stderr_len = int(stderr_len) except Exception: raise errors.AnsibleError("stderr size from remote end is unexpected: %r" % stderr_len) if stdout_len > 1024*1024*1024 or stdout_len < 0: raise errors.AnsibleError("stderr size from remote end is invalid: %s" % stderr_len) stderr = self._transport.stdout.read(stderr_len) if stderr_len != 0 else '' if len(stderr) != stderr_len: raise errors.AnsibleError("stderr size from remote end does not match actual stderr length: %s != %s" % (stderr_len, len(stderr))) return (retcode, stdout, stderr) except Exception: self._abort_transport() raise elif yesno == "N\n": exc = decode_exception(self._transport.stdin) raise exc else: self._abort_transport() raise errors.AnsibleError("pass/fail from remote end is unexpected: %r" % yesno)
def wrapped(self, *args, **kwargs): if not self.initialized: display.vvvv("Initial connection to galaxy_server: %s" % self._api_server) server_version = self._get_server_api_version() if server_version not in self.SUPPORTED_VERSIONS: raise AnsibleError("Unsupported Galaxy server API version: %s" % server_version) self.baseurl = '%s/api/%s' % (self._api_server, server_version) self.version = server_version # for future use display.vvvv("Base API: %s" % self.baseurl) self.initialized = True return method(self, *args, **kwargs)
def find_plugins(self, path, ptype): display.vvvv("Searching %s for plugins" % path) if not os.path.exists(path): display.vvvv("%s does not exist" % path) return bkey = ptype.upper() for plugin in os.listdir(path): display.vvvv("Found %s" % plugin) full_path = '/'.join([path, plugin]) if plugin.startswith('.'): continue elif os.path.isdir(full_path): continue elif any(plugin.endswith(x) for x in C.BLACKLIST_EXTS): continue elif plugin.startswith('__'): continue elif plugin in C.IGNORE_FILES: continue elif plugin .startswith('_'): if os.path.islink(full_path): # avoids aliases continue plugin = os.path.splitext(plugin)[0] # removes the extension plugin = plugin.lstrip('_') # remove underscore from deprecated plugins if plugin not in plugin_docs.BLACKLIST.get(bkey, ()): self.plugin_list.add(plugin) display.vvvv("Added %s" % plugin)
def run(self, terms, variables=None, **kwargs): display.vvvv(terms) if isinstance(terms, list): return_values = [] for term in terms: display.vvvv("Term: %s" % term) cyberark_conn = CyberarkPassword(**term) return_values.append(cyberark_conn.get()) return return_values else: cyberark_conn = CyberarkPassword(**terms) result = cyberark_conn.get() return result
def _load_conf_from_file(conf_path): display.vvv('conf file: {0}'.format(conf_path)) if not os.path.exists(conf_path): raise AnsibleError('Conjur configuration file `{0}` was not found on the controlling host' .format(conf_path)) display.vvvv('Loading configuration from: {0}'.format(conf_path)) with open(conf_path) as f: config = yaml.safe_load(f.read()) if 'account' not in config or 'appliance_url' not in config: raise AnsibleError('{0} on the controlling host must contain an `account` and `appliance_url` entry' .format(conf_path)) return config
def run(self, terms, **kwargs): if not HAS_KEYRING: raise AnsibleError(u"Can't LOOKUP(keyring): missing required python library 'keyring'") display.vvvv(u"keyring: %s" % keyring.get_keyring()) ret = [] for term in terms: (servicename, username) = (term.split()[0], term.split()[1]) display.vvvv(u"username: %s, servicename: %s " % (username, servicename)) password = keyring.get_password(servicename, username) if password is None: raise AnsibleError(u"servicename: %s for user %s not found" % (servicename, username)) ret.append(password.rstrip()) return ret
def send(self, command, prompt=None, answer=None, newline=True, sendonly=False, prompt_retry_check=False): ''' Sends the command to the device in the opened shell ''' try: self._history.append(command) self._ssh_shell.sendall(b'%s\r' % command) if sendonly: return response = self.receive(command, prompt, answer, newline, prompt_retry_check) return to_text(response, errors='surrogate_or_strict') except (socket.timeout, AttributeError): display.vvvv(traceback.format_exc(), host=self._play_context.remote_addr) raise AnsibleConnectionFailure("timeout trying to send command: %s" % command.strip())
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection) play_context = copy.deepcopy(self._play_context) play_context.network_os = self._get_network_os(task_vars) self.provider = self._load_provider(play_context.network_os) if play_context.network_os == 'junos': play_context.connection = 'netconf' play_context.port = int(self.provider['port'] or self._play_context.port or 830) elif self.provider.get('transport') in ( 'nxapi', 'eapi') and play_context.network_os in ('nxos', 'eos'): play_context.connection = play_context.connection play_context.port = int(self.provider['port'] or self._play_context.port or 22) else: play_context.connection = 'network_cli' play_context.port = int(self.provider['port'] or self._play_context.port or 22) play_context.remote_addr = self.provider[ 'host'] or self._play_context.remote_addr play_context.remote_user = self.provider[ 'username'] or self._play_context.connection_user play_context.password = self.provider[ 'password'] or self._play_context.password play_context.private_key_file = self.provider[ 'ssh_keyfile'] or self._play_context.private_key_file play_context.timeout = int(self.provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) if 'authorize' in self.provider.keys(): play_context.become = self.provider['authorize'] or False play_context.become_pass = self.provider['auth_pass'] if self.provider.get( 'transport') == 'nxapi' and play_context.network_os == 'nxos': self._task.args[ 'provider'] = _NxosActionModule.nxapi_implementation( self.provider, self._play_context) elif self.provider.get( 'transport') == 'eapi' and play_context.network_os == 'eos': self._task.args['provider'] = _EosActionModule.eapi_implementation( self.provider, self._play_context) else: socket_path = self._start_connection(play_context) task_vars['ansible_socket'] = socket_path if 'fail_on_missing_module' not in self._task.args: self._task.args['fail_on_missing_module'] = False result = super(ActionModule, self).run(tmp, task_vars) module = self._get_implementation_module(play_context.network_os, self._task.action) if not module: if self._task.args['fail_on_missing_module']: result['failed'] = True else: result['failed'] = False result['msg'] = ('Could not find implementation module %s for %s' % (self._task.action, play_context.network_os)) else: new_module_args = self._task.args.copy() # perhaps delete the provider argument here as well since the # module code doesn't need the information, the connection is # already started if 'network_os' in new_module_args: del new_module_args['network_os'] del new_module_args['fail_on_missing_module'] display.vvvv('Running implementation module %s' % module) result.update( self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task. async)) display.vvvv('Caching network OS %s in facts' % play_context.network_os) result['ansible_facts'] = {'network_os': play_context.network_os} return result
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection) provider = load_provider(ironware_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'ironware' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider[ 'username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider[ 'ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) pc.become = provider['authorize'] or False if pc.become: pc.become_method = 'enable' pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return { 'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell' } # make sure we are in the right cli context which should be # enable mode and not config module conn = Connection(socket_path) out = conn.get_prompt() if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'): display.vvvv('wrong context, sending end to device', self._play_context.remote_addr) conn.send_command('end') task_vars['ansible_socket'] = socket_path if self._play_context.become_method == 'enable': self._play_context.become = False self._play_context.become_method = None result = super(ActionModule, self).run(tmp, task_vars) return result
def _start_connection(self, variables): ''' Starts the persistent connection ''' candidate_paths = [ C.ANSIBLE_CONNECTION_PATH or os.path.dirname(sys.argv[0]) ] candidate_paths.extend(os.environ['PATH'].split(os.pathsep)) for dirname in candidate_paths: ansible_connection = os.path.join(dirname, 'ansible-connection') if os.path.isfile(ansible_connection): break else: raise AnsibleError( "Unable to find location of 'ansible-connection'. " "Please set or check the value of ANSIBLE_CONNECTION_PATH") python = sys.executable master, slave = pty.openpty() p = subprocess.Popen( [python, ansible_connection, to_text(os.getppid())], stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE) os.close(slave) # We need to set the pty into noncanonical mode. This ensures that we # can receive lines longer than 4095 characters (plus newline) without # truncating. old = termios.tcgetattr(master) new = termios.tcgetattr(master) new[3] = new[3] & ~termios.ICANON try: termios.tcsetattr(master, termios.TCSANOW, new) write_to_file_descriptor(master, variables) write_to_file_descriptor(master, self._play_context.serialize()) (stdout, stderr) = p.communicate() finally: termios.tcsetattr(master, termios.TCSANOW, old) os.close(master) if p.returncode == 0: result = json.loads( to_text(stdout, errors='surrogate_then_replace')) else: try: result = json.loads( to_text(stderr, errors='surrogate_then_replace')) except getattr(json.decoder, 'JSONDecodeError', ValueError): # JSONDecodeError only available on Python 3.5+ result = { 'error': to_text(stderr, errors='surrogate_then_replace') } if 'messages' in result: for msg in result.get('messages'): display.vvvv('%s' % msg, host=self._play_context.remote_addr) if 'error' in result: if self._play_context.verbosity > 2: if result.get('exception'): msg = "The full traceback is:\n" + result['exception'] display.display(msg, color=C.COLOR_ERROR) raise AnsibleError(result['error']) return result['socket_path']
def run(self, terms, variables=None, boto_profile=None, aws_profile=None, aws_secret_key=None, aws_access_key=None, aws_security_token=None, region=None, bypath=False, shortnames=False, recursive=False, decrypt=True): ''' :arg terms: a list of lookups to run. e.g. ['parameter_name', 'parameter_name_too' ] :kwarg variables: ansible variables active at the time of the lookup :kwarg aws_secret_key: identity of the AWS key to use :kwarg aws_access_key: AWS seret key (matching identity) :kwarg aws_security_token: AWS session key if using STS :kwarg decrypt: Set to True to get decrypted parameters :kwarg region: AWS region in which to do the lookup :kwarg bypath: Set to True to do a lookup of variables under a path :kwarg recursive: Set to True to recurse below the path (requires bypath=True) :returns: A list of parameter values or a list of dictionaries if bypath=True. ''' if not HAS_BOTO3: raise AnsibleError( 'botocore and boto3 are required for aws_ssm lookup.') ret = [] response = {} ssm_dict = {} credentials = {} if aws_profile: credentials['boto_profile'] = aws_profile else: credentials['boto_profile'] = boto_profile credentials['aws_secret_access_key'] = aws_secret_key credentials['aws_access_key_id'] = aws_access_key credentials['aws_session_token'] = aws_security_token client = _boto3_conn(region, credentials) ssm_dict['WithDecryption'] = decrypt # Lookup by path if bypath: ssm_dict['Recursive'] = recursive for term in terms: ssm_dict["Path"] = term display.vvv("AWS_ssm path lookup term: %s in region: %s" % (term, region)) try: response = client.get_parameters_by_path(**ssm_dict) except ClientError as e: raise AnsibleError("SSM lookup exception: {0}".format( to_native(e))) paramlist = list() paramlist.extend(response['Parameters']) # Manual pagination, since boto doesn't support it yet for get_parameters_by_path while 'NextToken' in response: response = client.get_parameters_by_path( NextToken=response['NextToken'], **ssm_dict) paramlist.extend(response['Parameters']) # shorten parameter names. yes, this will return duplicate names with different values. if shortnames: for x in paramlist: x['Name'] = x['Name'][x['Name'].rfind('/') + 1:] display.vvvv("AWS_ssm path lookup returned: %s" % str(paramlist)) if len(paramlist): ret.append( boto3_tag_list_to_ansible_dict( paramlist, tag_name_key_name="Name", tag_value_key_name="Value")) else: ret.append({}) # Lookup by parameter name - always returns a list with one or no entry. else: display.vvv("AWS_ssm name lookup term: %s" % terms) ssm_dict["Names"] = terms try: response = client.get_parameters(**ssm_dict) except ClientError as e: raise AnsibleError("SSM lookup exception: {0}".format( to_native(e))) params = boto3_tag_list_to_ansible_dict(response['Parameters'], tag_name_key_name="Name", tag_value_key_name="Value") for i in terms: if i in params: ret.append(params[i]) elif i in response['InvalidParameters']: ret.append(None) else: raise AnsibleError( "Ansible internal error: aws_ssm lookup failed to understand boto3 return value: {0}" .format(str(response))) return ret display.vvvv("AWS_ssm path lookup returning: %s " % str(ret)) return ret
def run(self, tmp=None, task_vars=None): transport = self._task.args.get('transport', 'rest') display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if self._play_context.connection == 'network_cli': provider = self._task.args.get('provider', {}) if any(provider.values()): display.warning( 'provider is unnecessary when using network_cli and will be ignored' ) elif self._play_context.connection == 'local': provider = load_provider(f5_provider_spec, self._task.args) transport = provider['transport'] or 'rest' display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if transport == 'cli': pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'bigip' pc.remote_addr = provider.get('server', self._play_context.remote_addr) pc.port = int(provider['server_port'] or self._play_context.port or 22) pc.remote_user = provider.get( 'user', self._play_context.connection_user) pc.password = provider.get('password', self._play_context.password) pc.private_key_file = provider[ 'ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int( provider.get('timeout', C.PERSISTENT_COMMAND_TIMEOUT)) display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return { 'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell' } task_vars['ansible_socket'] = socket_path else: self._task.args['provider'] = ActionModule.rest_implementation( provider, self._play_context) else: return { 'failed': True, 'msg': 'Connection type %s is not valid for this module' % self._play_context.connection } if (self._play_context.connection == 'local' and transport == 'cli') or self._play_context.connection == 'network_cli': # make sure we are in the right cli context which should be # enable mode and not config module if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() while '(config' in to_text( out, errors='surrogate_then_replace').strip(): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('exit') out = conn.get_prompt() result = super(ActionModule, self).run(tmp, task_vars) return result
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection) provider = self.load_provider() transport = provider['transport'] or 'cli' display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if transport == 'cli': pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'ce' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port']) or int( self._play_context.port) or 22 pc.remote_user = provider[ 'username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.timeout = provider['timeout'] or self._play_context.timeout self._task.args['provider'] = provider.update( host=pc.remote_addr, port=pc.port, username=pc.remote_user, password=pc.password, ssh_keyfile=pc.private_key_file) display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) socket_path = self._get_socket_path(pc) display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not os.path.exists(socket_path): # start the connection if it isn't started rc, out, err = connection.exec_command('open_shell()') display.vvvv('open_shell() returned %s %s %s' % (rc, out, err)) if rc != 0: return { 'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell', 'rc': rc } else: # make sure we are in the right cli context which should be # enable mode and not config module rc, out, err = connection.exec_command('prompt()') while str(out).strip().endswith(']'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) connection.exec_command('return') rc, out, err = connection.exec_command('prompt()') task_vars['ansible_socket'] = socket_path # make sure a transport value is set in args self._task.args['transport'] = transport self._task.args['provider'] = provider result = super(ActionModule, self).run(tmp, task_vars) return result
def run(self, tmp=None, task_vars=None): socket_path = None if self._play_context.connection == 'local': provider = load_provider(eos_provider_spec, self._task.args) transport = provider['transport'] or 'cli' display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if transport == 'cli': pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'eos' pc.remote_addr = provider[ 'host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider[ 'username'] or self._play_context.connection_user pc.password = provider[ 'password'] or self._play_context.password pc.private_key_file = provider[ 'ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) pc.become = provider['authorize'] or False if pc.become: pc.become_method = 'enable' pc.become_pass = provider['auth_pass'] display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return { 'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell' } task_vars['ansible_socket'] = socket_path else: provider['transport'] = 'eapi' if provider.get('host') is None: provider['host'] = self._play_context.remote_addr if provider.get('port') is None: default_port = 443 if provider['use_ssl'] else 80 provider['port'] = int(self._play_context.port or default_port) if provider.get('timeout') is None: provider['timeout'] = C.PERSISTENT_COMMAND_TIMEOUT if provider.get('username') is None: provider['username'] = self._play_context.connection_user if provider.get('password') is None: provider['password'] = self._play_context.password if provider.get('authorize') is None: provider['authorize'] = False self._task.args['provider'] = provider if (self._play_context.connection == 'local' and transport == 'cli') or self._play_context.connection == 'network_cli': # make sure we are in the right cli context which should be # enable mode and not config module if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() while '(config' in to_text( out, errors='surrogate_then_replace').strip(): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('abort') out = conn.get_prompt() result = super(ActionModule, self).run(tmp, task_vars) return result
def _connect(self): ''' Connects to the remote device and starts the terminal ''' if self.connected: return self.paramiko_conn = connection_loader.get('paramiko', self._play_context, '/dev/null') self.paramiko_conn.set_options( direct={ 'look_for_keys': not bool(self._play_context.password and not self._play_context.private_key_file) }) self.paramiko_conn.force_persistence = self.force_persistence ssh = self.paramiko_conn._connect() display.vvvv('ssh connection done, setting terminal', host=self._play_context.remote_addr) self._ssh_shell = ssh.ssh.invoke_shell() self._ssh_shell.settimeout(self._play_context.timeout) network_os = self._play_context.network_os if not network_os: raise AnsibleConnectionFailure( 'Unable to automatically determine host network os. Please ' 'manually configure ansible_network_os value for this host') self._terminal = terminal_loader.get(network_os, self) if not self._terminal: raise AnsibleConnectionFailure('network os %s is not supported' % network_os) display.vvvv('loaded terminal plugin for network_os %s' % network_os, host=self._play_context.remote_addr) self._cliconf = cliconf_loader.get(network_os, self) if self._cliconf: display.vvvv('loaded cliconf plugin for network_os %s' % network_os, host=self._play_context.remote_addr) else: display.vvvv('unable to load cliconf for network_os %s' % network_os) self.receive() display.vvvv('firing event: on_open_shell()', host=self._play_context.remote_addr) self._terminal.on_open_shell() if self._play_context.become and self._play_context.become_method == 'enable': display.vvvv('firing event: on_become', host=self._play_context.remote_addr) auth_pass = self._play_context.become_pass self._terminal.on_become(passwd=auth_pass) display.vvvv('ssh connection has completed successfully', host=self._play_context.remote_addr) self._connected = True return self
def run(self, tmp=None, task_vars=None): del tmp # tmp no longer has any effect socket_path = None if (self._play_context.connection == 'httpapi' or self._task.args.get('provider', {}).get('transport') == 'nxapi') \ and self._task.action == 'nxos_nxapi': return { 'failed': True, 'msg': "Transport type 'nxapi' is not valid for '%s' module." % (self._task.action) } if self._play_context.connection in ('network_cli', 'httpapi'): provider = self._task.args.get('provider', {}) if any(provider.values()): display.warning( 'provider is unnecessary when using %s and will be ignored' % self._play_context.connection) del self._task.args['provider'] if self._task.args.get('transport'): display.warning( 'transport is unnecessary when using %s and will be ignored' % self._play_context.connection) del self._task.args['transport'] elif self._play_context.connection == 'local': provider = load_provider(nxos_provider_spec, self._task.args) transport = provider['transport'] or 'cli' display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if transport == 'cli': pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'nxos' pc.remote_addr = provider[ 'host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider[ 'username'] or self._play_context.connection_user pc.password = provider[ 'password'] or self._play_context.password pc.private_key_file = provider[ 'ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int( provider['timeout']) if provider['timeout'] else None pc.become = provider['authorize'] or False if pc.become: pc.become_method = 'enable' pc.become_pass = provider['auth_pass'] display.vvv( 'using connection plugin %s (was local)' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) if connection._play_context.timeout is None: connection._play_context.timeout = connection.get_option( 'persistent_command_timeout') socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return { 'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell' } task_vars['ansible_socket'] = socket_path else: self._task.args[ 'provider'] = ActionModule.nxapi_implementation( provider, self._play_context) else: return { 'failed': True, 'msg': 'Connection type %s is not valid for this module' % self._play_context.connection } if (self._play_context.connection == 'local' and transport == 'cli') or self._play_context.connection == 'network_cli': # make sure we are in the right cli context which should be # enable mode and not config module if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() while to_text( out, errors='surrogate_then_replace').strip().endswith(')#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('exit') out = conn.get_prompt() result = super(ActionModule, self).run(task_vars=task_vars) return result
def run(self, tmp=None, task_vars=None): del tmp # tmp no longer has any effect socket_path = None if self._play_context.connection == 'local': provider = load_provider(ce_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'ce' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider['username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password command_timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) self._task.args['provider'] = provider.update( host=pc.remote_addr, port=pc.port, username=pc.remote_user, password=pc.password ) if self._task.action in ['ce_netconf'] or self._task.action not in CLI_SUPPORTED_MODULES: pc.connection = 'netconf' display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) connection.set_options(direct={'persistent_command_timeout': command_timeout}) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return {'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} task_vars['ansible_socket'] = socket_path self._task.args['provider'] = provider elif self._play_context.connection in ('netconf', 'network_cli'): provider = self._task.args.get('provider', {}) if any(provider.values()): display.warning('provider is unnessary whene using %s and will be ignored' % self._play_context.connection) del self._task.args['provider'] if (self._play_context.connection == 'network_cli' and self._task.action not in CLI_SUPPORTED_MODULES) or \ (self._play_context.connection == 'netconf' and self._task.action in CLI_SUPPORTED_MODULES): return {'failed': True, 'msg': "Connection type '%s' is not valid for '%s' module." % (self._play_context.connection, self._task.action)} if (self._play_context.connection == 'local' and self._task.action in CLI_SUPPORTED_MODULES) \ or self._play_context.connection == 'network_cli': # make sure we are in the right cli context whitch should be # enable mode and not config module if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() while to_text(out, errors='surrogate_then_replace').strip().endswith(']'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('exit') out = conn.get_prompt() result = super(ActionModule, self).run(task_vars=task_vars) return result
def decrypt(self, vaulttext, filename=None): """Decrypt a piece of vault encrypted data. :arg vaulttext: a string to decrypt. Since vault encrypted data is an ascii text format this can be either a byte str or unicode string. :kwarg filename: a filename that the data came from. This is only used to make better error messages in case the data cannot be decrypted. :returns: a byte string containing the decrypted data """ b_vaulttext = to_bytes(vaulttext, errors='strict', encoding='utf-8') if self.secrets is None: raise AnsibleVaultError( "A vault password must be specified to decrypt data") if not is_encrypted(b_vaulttext): msg = "input is not vault encrypted data" if filename: msg += "%s is not a vault encrypted file" % filename raise AnsibleError(msg) b_vaulttext, b_version, cipher_name, vault_id = parse_vaulttext_envelope( b_vaulttext) # create the cipher object, note that the cipher used for decrypt can # be different than the cipher used for encrypt if cipher_name in CIPHER_WHITELIST: this_cipher = CIPHER_MAPPING[cipher_name]() else: raise AnsibleError( "{0} cipher could not be found".format(cipher_name)) b_plaintext = None if not self.secrets: raise AnsibleVaultError( 'Attempting to decrypt but no vault secrets found') # WARNING: Currently, the vault id is not required to match the vault id in the vault blob to # decrypt a vault properly. The vault id in the vault blob is not part of the encrypted # or signed vault payload. There is no cryptographic checking/verification/validation of the # vault blobs vault id. It can be tampered with and changed. The vault id is just a nick # name to use to pick the best secret and provide some ux/ui info. # iterate over all the applicable secrets (all of them by default) until one works... # if we specify a vault_id, only the corresponding vault secret is checked and # we check it first. vault_id_matchers = [] if vault_id: display.vvvvv('Found a vault_id (%s) in the vaulttext' % (vault_id)) vault_id_matchers.append(vault_id) _matches = match_secrets(self.secrets, vault_id_matchers) if _matches: display.vvvvv( 'We have a secret associated with vault id (%s), will try to use to decrypt %s' % (vault_id, filename)) else: display.vvvvv( 'Found a vault_id (%s) in the vault text, but we do not have a associated secret (--vault-id)' % (vault_id)) # Not adding the other secrets to vault_secret_ids enforces a match between the vault_id from the vault_text and # the known vault secrets. if not C.DEFAULT_VAULT_ID_MATCH: # Add all of the known vault_ids as candidates for decrypting a vault. vault_id_matchers.extend([ _vault_id for _vault_id, _secret in self.secrets if _vault_id != vault_id ]) matched_secrets = match_secrets(self.secrets, vault_id_matchers) # for vault_secret_id in vault_secret_ids: for vault_secret_id, vault_secret in matched_secrets: display.vvvvv( 'Trying to use vault secret=(%s) id=%s to decrypt %s' % (vault_secret, vault_secret_id, filename)) try: # secret = self.secrets[vault_secret_id] display.vvvv('Trying secret %s for vault_id=%s' % (vault_secret, vault_secret_id)) b_plaintext = this_cipher.decrypt(b_vaulttext, vault_secret) if b_plaintext is not None: display.vvvvv( 'decrypt succesful with secret=%s and vault_id=%s' % (vault_secret, vault_secret_id)) break except AnsibleError as e: display.vvvv( 'Tried to use the vault secret (%s) to decrypt (%s) but it failed. Error: %s' % (vault_secret_id, filename, e)) continue else: msg = "Decryption failed (no vault secrets would found that could decrypt)" if filename: msg += " on %s" % filename raise AnsibleVaultError(msg) if b_plaintext is None: msg = "Decryption failed" if filename: msg += " on %s" % filename raise AnsibleError(msg) return b_plaintext
def run(self, tmp=None, task_vars=None): del tmp # tmp no longer has any effect socket_path = None play_context = copy.deepcopy(self._play_context) play_context.network_os = self._get_network_os(task_vars) if play_context.connection == 'local': # we should be able to stream line this a bit by creating a common # provider argument spec in module_utils/network/common/utils.py or another # option is that there isn't a need to push provider into the module # since the connection is started in the action handler. module_name = 'ansible.module_utils.network.{0}.{0}'.format(play_context.network_os) f, p, d = find_module('ansible') for package in module_name.split('.')[1:]: f, p, d = find_module(package, [p]) module = load_module(module_name, f, p, d) self.provider = load_provider(module.get_provider_argspec(), self._task.args) if self.provider.get('transport') == 'netconf' and play_context.network_os in _NETCONF_SUPPORTED_PLATFORMS \ and self._task.action not in _CLI_ONLY_MODULES: play_context.connection = 'netconf' play_context.port = int(self.provider['port'] or self._play_context.port or 830) elif self.provider.get('transport') in ('nxapi', 'eapi') and play_context.network_os in ('nxos', 'eos'): play_context.connection = play_context.connection play_context.port = int(self.provider['port'] or self._play_context.port or 22) else: play_context.connection = 'network_cli' play_context.port = int(self.provider['port'] or self._play_context.port or 22) play_context.remote_addr = self.provider['host'] or self._play_context.remote_addr play_context.remote_user = self.provider['username'] or self._play_context.connection_user play_context.password = self.provider['password'] or self._play_context.password play_context.private_key_file = self.provider['ssh_keyfile'] or self._play_context.private_key_file play_context.timeout = int(self.provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) if 'authorize' in self.provider.keys(): play_context.become = self.provider['authorize'] or False play_context.become_pass = self.provider['auth_pass'] play_context.become_method = 'enable' if self._play_context.connection == 'local': if self.provider.get('transport') == 'nxapi' and play_context.network_os == 'nxos': self._task.args['provider'] = _NxosActionModule.nxapi_implementation(self.provider, self._play_context) elif self.provider.get('transport') == 'eapi' and play_context.network_os == 'eos': self._task.args['provider'] = _EosActionModule.eapi_implementation(self.provider, self._play_context) else: socket_path = self._start_connection(play_context) task_vars['ansible_socket'] = socket_path else: provider = self._task.args.get('provider', {}) if any(provider.values()): display.warning('provider is unnecessary when using %s and will be ignored' % play_context.connection) del self._task.args['provider'] if play_context.connection == 'network_cli': # make sure we are in the right cli context which should be # enable mode and not config module if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() if to_text(out, errors='surrogate_then_replace').strip().endswith(')#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('exit') if 'fail_on_missing_module' not in self._task.args: self._task.args['fail_on_missing_module'] = False result = super(ActionModule, self).run(task_vars=task_vars) module = self._get_implementation_module(play_context.network_os, self._task.action) if not module: if self._task.args['fail_on_missing_module']: result['failed'] = True else: result['failed'] = False result['msg'] = ('Could not find implementation module %s for %s' % (self._task.action, play_context.network_os)) else: new_module_args = self._task.args.copy() # perhaps delete the provider argument here as well since the # module code doesn't need the information, the connection is # already started if 'network_os' in new_module_args: del new_module_args['network_os'] del new_module_args['fail_on_missing_module'] display.vvvv('Running implementation module %s' % module) result.update(self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task.async_val)) display.vvvv('Caching network OS %s in facts' % play_context.network_os) result['ansible_facts'] = {'network_os': play_context.network_os} return result
def _handle_buffer_read_timeout(self, signum, frame): display.vvvv("Response received, triggered 'persistent_buffer_read_timeout' timer of %s seconds" % self.get_option('persistent_buffer_read_timeout'), host=self._play_context.remote_addr) raise AnsibleCmdRespRecv()
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection ) provider = self.load_provider() transport = provider['transport'] or 'cli' display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if transport == 'cli': pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'nxos' pc.port = provider['port'] or self._play_context.port or 22 pc.remote_user = provider['username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file pc.timeout = provider['timeout'] or self._play_context.timeout connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = self._get_socket_path(pc) display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not os.path.exists(socket_path): # start the connection if it isn't started rc, out, err = connection.exec_command('open_shell()') display.vvvv('open_shell() returned %s %s %s' % (rc, out, err)) if rc != 0: return {'failed': True, 'msg': 'unable to open shell', 'rc': rc} else: # make sure we are in the right cli context which should be # enable mode and not config module rc, out, err = connection.exec_command('prompt()') while str(out).strip().endswith(')#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) connection.exec_command('exit') rc, out, err = connection.exec_command('prompt()') task_vars['ansible_socket'] = socket_path else: provider['transport'] = 'nxapi' if provider.get('host') is None: provider['host'] = self._play_context.remote_addr if provider.get('port') is None: provider['port'] = 80 if provider.get('timeout') is None: provider['timeout'] = self._play_context.timeout if provider.get('username') is None: provider['username'] = self._play_context.connection_user if provider.get('password') is None: provider['password'] = self._play_context.password if provider.get('use_ssl') is None: provider['use_ssl'] = False if provider.get('validate_certs') is None: provider['validate_certs'] = True self._task.args['provider'] = provider # make sure a transport value is set in args self._task.args['transport'] = transport return super(ActionModule, self).run(tmp, task_vars)
def _connect(self): ''' Connects to the remote device and starts the terminal ''' if not self.connected: if not self._network_os: raise AnsibleConnectionFailure( 'Unable to automatically determine host network os. Please ' 'manually configure ansible_network_os value for this host' ) display.display('network_os is set to %s' % self._network_os, log_only=True) self.paramiko_conn = connection_loader.get('paramiko', self._play_context, '/dev/null') self.paramiko_conn._set_log_channel(self._get_log_channel()) self.paramiko_conn.set_options(direct={'look_for_keys': not bool(self._play_context.password and not self._play_context.private_key_file)}) self.paramiko_conn.force_persistence = self.force_persistence ssh = self.paramiko_conn._connect() host = self.get_option('host') display.vvvv('ssh connection done, setting terminal', host=host) self._ssh_shell = ssh.ssh.invoke_shell() self._ssh_shell.settimeout(self.get_option('persistent_command_timeout')) self._terminal = terminal_loader.get(self._network_os, self) if not self._terminal: raise AnsibleConnectionFailure('network os %s is not supported' % self._network_os) display.vvvv('loaded terminal plugin for network_os %s' % self._network_os, host=host) self.cliconf = cliconf_loader.get(self._network_os, self) if self.cliconf: display.vvvv('loaded cliconf plugin for network_os %s' % self._network_os, host=host) self._implementation_plugins.append(self.cliconf) else: display.vvvv('unable to load cliconf for network_os %s' % self._network_os) super(Connection, self)._connect() self.receive(prompts=self._terminal.terminal_initial_prompt, answer=self._terminal.terminal_initial_answer, newline=self._terminal.terminal_inital_prompt_newline) display.vvvv('firing event: on_open_shell()', host=host) self._terminal.on_open_shell() if self._play_context.become and self._play_context.become_method == 'enable': display.vvvv('firing event: on_become', host=host) auth_pass = self._play_context.become_pass self._terminal.on_become(passwd=auth_pass) display.vvvv('ssh connection has completed successfully', host=host) self._connected = True return self
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection) play_context = copy.deepcopy(self._play_context) play_context.network_os = self._get_network_os(task_vars) # TODO this can be netconf play_context.connection = 'network_cli' self.provider = self._load_provider(play_context.network_os) play_context.remote_addr = self.provider[ 'host'] or self._play_context.remote_addr play_context.port = self.provider[ 'port'] or self._play_context.port or 22 play_context.remote_user = self.provider[ 'username'] or self._play_context.connection_user play_context.password = self.provider[ 'password'] or self._play_context.password play_context.private_key_file = self.provider[ 'ssh_keyfile'] or self._play_context.private_key_file play_context.timeout = self.provider[ 'timeout'] or self._play_context.timeout if 'authorize' in self.provider.keys(): play_context.become = self.provider['authorize'] or False play_context.become_pass = self.provider['auth_pass'] socket_path = self._start_connection(play_context) task_vars['ansible_socket'] = socket_path result = super(ActionModule, self).run(tmp, task_vars) module = self._get_implementation_module(play_context.network_os, self._task.action) if not module: result['failed'] = True result['msg'] = ('Could not find implementation module %s for %s' % (self._task.action, play_context.network_os)) else: new_module_args = self._task.args.copy() # perhaps delete the provider argument here as well since the # module code doesn't need the information, the connection is # already started if 'network_os' in new_module_args: del new_module_args['network_os'] display.vvvv('Running implementation module %s' % module) result.update( self._execute_module(module_name=module, module_args=new_module_args, task_vars=task_vars, wrap_async=self._task. async)) display.vvvv('Caching network OS %s in facts' % play_context.network_os) result['ansible_facts'] = {'network_os': play_context.network_os} return result
def exec_command(self, cmd, in_data=None, sudoable=True): display.vvvv('exec_command(), socket_path=%s' % self.socket_path, host=self._play_context.remote_addr) connection = SocketConnection(self.socket_path) out = connection.exec_command(cmd, in_data=in_data, sudoable=sudoable) return 0, out, ''
def connection_unlock(self): f = self._play_context.connection_lockfd fcntl.lockf(f, fcntl.LOCK_UN) display.vvvv('CONNECTION: pid %d released lock on %d' % (os.getpid(), f))
def run(self, terms, variables=None, **kwargs): if len(terms) > 0 and isinstance(terms, dict): # to do, use terms to specify the options display.vvvv('terms is a dict') else: length = int(kwargs.get('length', 12)) special_characters = kwargs.pop('special_characters', SPECIAL_CHARACTERS) forbidden_characters = kwargs.pop('forbidden_characters', '') prevent_repeating_characters = kwargs.pop( 'prevent_repeating_characters', True) min_upper_case = int(kwargs.pop('min_upper_case', 2)) min_lower_case = int(kwargs.pop('min_lower_case', 2)) min_digit = int(kwargs.pop('min_digit', 2)) min_special = int(kwargs.pop('min_special', 2)) if 1 > length or length > 128: raise AnsibleError("valid length must be in range 1 - 128") display.vvvv('length: %s' % (length)) display.vvvv('min_upper_case: %s' % (min_upper_case)) display.vvvv('min_lower_case: %s' % (min_lower_case)) display.vvvv('min_digit: %s' % (min_digit)) display.vvvv('min_special: %s' % (min_special)) display.vvvv('special_characters: %s' % (special_characters)) display.vvvv('forbidden_characters: %s' % (forbidden_characters)) display.vvvv('prevent_repeating_characters: %s' % (prevent_repeating_characters)) results = [] params = {} params['length'] = length params['min_upper_case'] = min_upper_case params['min_lower_case'] = min_lower_case params['min_digit'] = min_digit params['min_special'] = min_special params['special_chars'] = special_characters params['forbidden_chars'] = forbidden_characters params['prevent_repeating_chars'] = prevent_repeating_characters try: complex_password = mkpasswd(**params) except ValueError as e: raise AnsibleError(to_text(e)) results.extend([complex_password]) return results
def run(self, tmp=None, task_vars=None): del tmp # tmp no longer has any effect module = module_loader._load_module_source(self._task.action, module_loader.find_plugin(self._task.action)) if not getattr(module, 'USE_PERSISTENT_CONNECTION', False): return super(ActionModule, self).run(task_vars=task_vars) socket_path = None if self._play_context.connection == 'local': provider = load_provider(junos_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) pc.network_os = 'junos' pc.remote_addr = provider['host'] or self._play_context.remote_addr if provider['transport'] == 'cli' and self._task.action not in CLI_SUPPORTED_MODULES: return {'failed': True, 'msg': "Transport type '%s' is not valid for '%s' module. " "Please see http://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html" % (provider['transport'], self._task.action)} if self._task.action == 'junos_netconf' or (provider['transport'] == 'cli' and self._task.action == 'junos_command'): pc.connection = 'network_cli' pc.port = int(provider['port'] or self._play_context.port or 22) else: pc.connection = 'netconf' pc.port = int(provider['port'] or self._play_context.port or 830) pc.remote_user = provider['username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider['ssh_keyfile'] or self._play_context.private_key_file pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s (was local)' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get('persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return {'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell'} task_vars['ansible_socket'] = socket_path elif self._play_context.connection in ('netconf', 'network_cli'): provider = self._task.args.get('provider', {}) if any(provider.values()): display.warning('provider is unnecessary when using connection=%s and will be ignored' % self._play_context.connection) if (self._play_context.connection == 'network_cli' and self._task.action not in CLI_SUPPORTED_MODULES) or \ (self._play_context.connection == 'netconf' and self._task.action == 'junos_netconf'): return {'failed': True, 'msg': "Connection type '%s' is not valid for '%s' module. " "Please see http://docs.ansible.com/ansible/latest/network/user_guide/platform_junos.html" % (self._play_context.connection, self._task.action)} if (self._play_context.connection == 'local' and pc.connection == 'network_cli') or self._play_context.connection == 'network_cli': # make sure we are in the right cli context which should be # enable mode and not config module if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() while to_text(out, errors='surrogate_then_replace').strip().endswith('#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('exit') out = conn.get_prompt() result = super(ActionModule, self).run(None, task_vars) return result
async_result = normal_handler.run(task_vars=task_vars) # We do not bail out of the loop in cases where the failure # is associated with a parsing error. The async_runner can # have issues which result in a half-written/unparseable result # file on disk, which manifests to the user as a timeout happening # before it's time to timeout. if (int(async_result.get('finished', 0)) == 1 or ('failed' in async_result and async_result.get('_ansible_parsed', False)) or 'skipped' in async_result): break except Exception as e: # Connections can raise exceptions during polling (eg, network bounce, reboot); these should be non-fatal. # On an exception, call the connection's reset method if it has one # (eg, drop/recreate WinRM connection; some reused connections are in a broken state) display.vvvv("Exception during async poll, retrying... (%s)" % to_text(e)) display.debug("Async poll exception was:\n%s" % to_text(traceback.format_exc())) try: normal_handler._connection._reset() except AttributeError: pass time_left -= self._task.poll if int(async_result.get('finished', 0)) != 1: if async_result.get('_ansible_parsed'): return dict( failed=True, msg="async task did not complete within the requested time" )
def parse_inventory(self, host_list): if isinstance(host_list, string_types): if "," in host_list: host_list = host_list.split(",") host_list = [h for h in host_list if h and h.strip()] self.parser = None # Always create the 'all' and 'ungrouped' groups, even if host_list is # empty: in this case we will subsequently an the implicit 'localhost' to it. ungrouped = Group('ungrouped') all = Group('all') all.add_child_group(ungrouped) self.groups = dict(all=all, ungrouped=ungrouped) if host_list is None: pass elif isinstance(host_list, list): for h in host_list: try: (host, port) = parse_address(h, allow_ranges=False) except AnsibleError as e: display.vvv( "Unable to parse address from hostname, leaving unchanged: %s" % to_unicode(e)) host = h port = None new_host = Host(host, port) if h in C.LOCALHOST: # set default localhost from inventory to avoid creating an implicit one. Last localhost defined 'wins'. if self.localhost is not None: display.warning( "A duplicate localhost-like entry was found (%s). First found localhost was %s" % (h, self.localhost.name)) display.vvvv("Set default localhost to %s" % h) self.localhost = new_host all.add_host(new_host) elif self._loader.path_exists(host_list): #TODO: switch this to a plugin loader and a 'condition' per plugin on which it should be tried, restoring 'inventory pllugins' if self.is_directory(host_list): # Ensure basedir is inside the directory host_list = os.path.join(self.host_list, "") self.parser = InventoryDirectory(loader=self._loader, groups=self.groups, filename=host_list) else: self.parser = get_file_parser(host_list, self.groups, self._loader) vars_loader.add_directory(self._basedir, with_subdir=True) if not self.parser: # should never happen, but JIC raise AnsibleError( "Unable to parse %s as an inventory source" % host_list) else: display.warning("Host file not found: %s" % to_unicode(host_list)) self._vars_plugins = [x for x in vars_loader.all(self)] # set group vars from group_vars/ files and vars plugins for g in self.groups: group = self.groups[g] group.vars = combine_vars(group.vars, self.get_group_variables(group.name)) self.get_group_vars(group) # get host vars from host_vars/ files and vars plugins for host in self.get_hosts(ignore_limits_and_restrictions=True): host.vars = combine_vars(host.vars, self.get_host_variables(host.name)) self.get_host_vars(host)
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection) module = module_loader._load_module_source( self._task.action, module_loader.find_plugin(self._task.action)) if not getattr(module, 'USE_PERSISTENT_CONNECTION', False): return super(ActionModule, self).run(tmp, task_vars) provider = self.load_provider() pc = copy.deepcopy(self._play_context) pc.network_os = 'junos' pc.remote_addr = provider['host'] or self._play_context.remote_addr if self._task.action == 'junos_netconf': pc.connection = 'network_cli' pc.port = provider['port'] or self._play_context.port or 22 else: pc.connection = 'netconf' pc.port = provider['port'] or self._play_context.port or 830 pc.remote_user = provider[ 'username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.private_key_file = provider[ 'ssh_keyfile'] or self._play_context.private_key_file pc.timeout = provider['timeout'] or self._play_context.timeout display.vvv('using connection plugin %s' % pc.connection) connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) socket_path = self._get_socket_path(pc) display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not os.path.exists(socket_path): # start the connection if it isn't started if pc.connection == 'netconf': rc, out, err = connection.exec_command('open_session()') else: rc, out, err = connection.exec_command('open_shell()') if rc != 0: return { 'failed': True, 'msg': 'unable to connect to control socket' } elif pc.connection == 'network_cli': # make sure we are in the right cli context which should be # enable mode and not config module rc, out, err = connection.exec_command('prompt()') while str(out).strip().endswith(')#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) connection.exec_command('exit') rc, out, err = connection.exec_command('prompt()') task_vars['ansible_socket'] = socket_path return super(ActionModule, self).run(tmp, task_vars)
def run(self, terms, variables, **kwargs): res = [] try: xml_data = terms[0] except IndexError: raise AnsibleError("Either xml string or path to xml file must be specified") try: yang_file = kwargs['yang_file'] except KeyError: raise AnsibleError("value of 'yang_file' must be specified") yang_file = os.path.realpath(os.path.expanduser(yang_file)) if not os.path.isfile(yang_file): # Maybe we are passing a glob? yang_files = glob.glob(yang_file) if not yang_files: # Glob returned no files raise AnsibleError('%s invalid file path' % yang_file) else: yang_files = [yang_file] search_path = kwargs.pop('search_path', '') keep_tmp_files = kwargs.pop('keep_tmp_files', False) abs_search_path = None for path in search_path.split(':'): path = os.path.realpath(os.path.expanduser(path)) if abs_search_path is None: abs_search_path = path else: abs_search_path += ':' + path if path is not '' and not os.path.isdir(path): raise AnsibleError('%s is invalid directory path' % path) search_path = abs_search_path plugindir = unfrackpath(XM2JSONL_DIR_PATH) makedirs_safe(plugindir) if os.path.isfile(xml_data): # input is xml file path xml_file_path = xml_data else: # input is xml string, copy it to file in temporary location xml_file_path = os.path.join(XM2JSONL_DIR_PATH, '%s.%s' % (str(uuid.uuid4()), 'xml')) xml_file_path = os.path.realpath(os.path.expanduser(xml_file_path)) with open(xml_file_path, 'w') as f: if not xml_data.startswith('<?xml version'): xml_data = '<?xml version="1.0" encoding="UTF-8"?>\n' + xml_data data = xml_data f.write(data) xml_file_path = os.path.realpath(os.path.expanduser(xml_file_path)) try: # validate xml etree.parse(xml_file_path) display.vvvv("Parsing xml data from temporary file: %s" % xml_file_path) except Exception as exc: if not keep_tmp_files: shutil.rmtree(os.path.realpath(os.path.expanduser(XM2JSONL_DIR_PATH)), ignore_errors=True) raise AnsibleError("Failed to load xml data: %s" % (to_text(exc, errors='surrogate_or_strict'))) base_pyang_path = sys.modules['pyang'].__file__ pyang_exec_path = find_file_in_path('pyang') pyang_exec = imp.load_source('pyang', pyang_exec_path) saved_arg = deepcopy(sys.argv) sys.modules['pyang'].__file__ = base_pyang_path saved_stdout = sys.stdout saved_stderr = sys.stderr sys.stdout = sys.stderr = StringIO() xsl_file_path = os.path.join(XM2JSONL_DIR_PATH, '%s.%s' % (str(uuid.uuid4()), 'xsl')) json_file_path = os.path.join(XM2JSONL_DIR_PATH, '%s.%s' % (str(uuid.uuid4()), 'json')) xls_file_path = os.path.realpath(os.path.expanduser(xsl_file_path)) json_file_path = os.path.realpath(os.path.expanduser(json_file_path)) # fill in the sys args before invoking pyang sys.argv = [pyang_exec_path, '-f', 'jsonxsl', '-o', xls_file_path, '-p', search_path, "--lax-quote-checks"] + yang_files display.display("Generating xsl file '%s' by executing command '%s'" % (xls_file_path, ' '.join(sys.argv)), log_only=True) try: pyang_exec.run() except SystemExit: pass except Exception as e: if not keep_tmp_files: shutil.rmtree(os.path.realpath(os.path.expanduser(XM2JSONL_DIR_PATH)), ignore_errors=True) raise AnsibleError('Error while generating intermediate (xsl) file: %s' % e) finally: err = sys.stderr.getvalue() if err and 'error' in err.lower(): if not keep_tmp_files: shutil.rmtree(os.path.realpath(os.path.expanduser(XM2JSONL_DIR_PATH)), ignore_errors=True) raise AnsibleError('Error while generating (xsl) intermediate file: %s' % err) xsltproc_exec_path = find_file_in_path('xsltproc') # fill in the sys args before invoking xsltproc sys.argv = [xsltproc_exec_path, '-o', json_file_path, xsl_file_path, xml_file_path] display.display("Generating json data in temp file '%s' by executing command '%s'" % (json_file_path, ' '.join(sys.argv)), log_only=True) time.sleep(5) try: os.system(' '.join(sys.argv)) except SystemExit: pass finally: err = sys.stderr.getvalue() if err and 'error' in err.lower(): if not keep_tmp_files: shutil.rmtree(os.path.realpath(os.path.expanduser(XM2JSONL_DIR_PATH)), ignore_errors=True) raise AnsibleError('Error while translating to json: %s' % err) sys.argv = saved_arg sys.stdout = saved_stdout sys.stderr = saved_stderr try: display.vvvv("Reading output json data from temporary file: %s" % json_file_path) with open(json_file_path) as fp: content = json.load(fp) except Exception as e: raise AnsibleError('Error while reading json document: %s' % e) finally: if not keep_tmp_files: shutil.rmtree(os.path.realpath(os.path.expanduser(XM2JSONL_DIR_PATH)), ignore_errors=True) res.append(content) return res
def put_file(self, in_path, out_path): ''' transfer a file from local to remote ''' display.vvv("PUT %s TO %s" % (in_path, out_path), host=self._play_context.remote_addr) in_path = to_bytes(in_path, errors='surrogate_or_strict') if not os.path.exists(in_path): raise AnsibleFileNotFound("file or module does not exist: %s" % in_path) fd = file(in_path, 'rb') fstat = os.stat(in_path) try: display.vvv("PUT file is %d bytes" % fstat.st_size, host=self._play_context.remote_addr) last = False while fd.tell() <= fstat.st_size and not last: display.vvvv("file position currently %ld, file size is %ld" % (fd.tell(), fstat.st_size), host=self._play_context.remote_addr) data = fd.read(CHUNK_SIZE) if fd.tell() >= fstat.st_size: last = True data = dict(mode='put', data=base64.b64encode(data), out_path=out_path, last=last) if self._play_context.become: data['user'] = self._play_context.become_user data = jsonify(data) data = keyczar_encrypt(self.key, data) if self.send_data(data): raise AnsibleError("failed to send the file to %s" % self._play_context.remote_addr) response = self.recv_data() if not response: raise AnsibleError("Failed to get a response from %s" % self._play_context.remote_addr) response = keyczar_decrypt(self.key, response) response = json.loads(response) if response.get('failed', False): raise AnsibleError( "failed to put the file in the requested location") finally: fd.close() display.vvvv("waiting for final response after PUT", host=self._play_context.remote_addr) response = self.recv_data() if not response: raise AnsibleError("Failed to get a response from %s" % self._play_context.remote_addr) response = keyczar_decrypt(self.key, response) response = json.loads(response) if response.get('failed', False): raise AnsibleError( "failed to put the file in the requested location")
def run(self, tmp=None, task_vars=None): socket_path = None if self._play_context.connection == 'network_cli': provider = self._task.args.get('provider', {}) if any(provider.values()): display.warning( 'provider is unnecessary when using network_cli and will be ignored' ) elif self._play_context.connection == 'local': provider = load_provider(iosxr_provider_spec, self._task.args) pc = copy.deepcopy(self._play_context) if self._task.action in ['iosxr_netconf', 'iosxr_config', 'iosxr_command'] or \ (provider['transport'] == 'cli' and (self._task.action == 'iosxr_banner' or self._task.action == 'iosxr_facts' or self._task.action == 'iosxr_logging' or self._task.action == 'iosxr_system' or self._task.action == 'iosxr_user' or self._task.action == 'iosxr_interface')): pc.connection = 'network_cli' pc.port = int(provider['port'] or self._play_context.port or 22) else: pc.connection = 'netconf' pc.port = int(provider['port'] or self._play_context.port or 830) pc.network_os = 'iosxr' pc.remote_addr = provider['host'] or self._play_context.remote_addr pc.port = int(provider['port'] or self._play_context.port or 22) pc.remote_user = provider[ 'username'] or self._play_context.connection_user pc.password = provider['password'] or self._play_context.password pc.timeout = int(provider['timeout'] or C.PERSISTENT_COMMAND_TIMEOUT) display.vvv('using connection plugin %s' % pc.connection, pc.remote_addr) connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) socket_path = connection.run() display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not socket_path: return { 'failed': True, 'msg': 'unable to open shell. Please see: ' + 'https://docs.ansible.com/ansible/network_debug_troubleshooting.html#unable-to-open-shell' } task_vars['ansible_socket'] = socket_path # make sure we are in the right cli context which should be # enable mode and not config module if (self._play_context.connection == 'local' and pc.connection == 'network_cli' ) or self._play_context.connection == 'network_cli': if socket_path is None: socket_path = self._connection.socket_path conn = Connection(socket_path) out = conn.get_prompt() while to_text( out, errors='surrogate_then_replace').strip().endswith(')#'): display.vvvv('wrong context, sending exit to device', self._play_context.remote_addr) conn.send_command('abort') out = conn.get_prompt() result = super(ActionModule, self).run(tmp, task_vars) return result
def connection_lock(self): f = self._play_context.connection_lockfd display.vvvv('CONNECTION: pid %d waiting for lock on %d' % (os.getpid(), f)) fcntl.lockf(f, fcntl.LOCK_EX) display.vvvv('CONNECTION: pid %d acquired lock on %d' % (os.getpid(), f))
def _start_connection(self): ''' Starts the persistent connection ''' master, slave = pty.openpty() python = sys.executable def find_file_in_path(filename): # Check $PATH first, followed by same directory as sys.argv[0] paths = os.environ['PATH'].split( os.pathsep) + [os.path.dirname(sys.argv[0])] for dirname in paths: fullpath = os.path.join(dirname, filename) if os.path.isfile(fullpath): return fullpath raise AnsibleError("Unable to find location of '%s'" % filename) p = subprocess.Popen([ python, find_file_in_path('ansible-connection'), to_text(os.getppid()) ], stdin=slave, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdin = os.fdopen(master, 'wb', 0) os.close(slave) # Need to force a protocol that is compatible with both py2 and py3. # That would be protocol=2 or less. # Also need to force a protocol that excludes certain control chars as # stdin in this case is a pty and control chars will cause problems. # that means only protocol=0 will work. src = cPickle.dumps(self._play_context.serialize(), protocol=0) stdin.write(src) stdin.write(b'\n#END_INIT#\n') stdin.flush() (stdout, stderr) = p.communicate() stdin.close() if p.returncode == 0: result = json.loads( to_text(stdout, errors='surrogate_then_replace')) else: try: result = json.loads( to_text(stderr, errors='surrogate_then_replace')) except getattr(json.decoder, 'JSONDecodeError', ValueError): # JSONDecodeError only available on Python 3.5+ result = { 'error': to_text(stderr, errors='surrogate_then_replace') } if 'messages' in result: for msg in result.get('messages'): display.vvvv('%s' % msg, host=self._play_context.remote_addr) if 'error' in result: if self._play_context.verbosity > 2: if result.get('exception'): msg = "The full traceback is:\n" + result['exception'] display.display(msg, color=C.COLOR_ERROR) raise AnsibleError(result['error']) return result['socket_path']
def _poll_async_result(self, result, templar, task_vars=None): ''' Polls for the specified JID to be complete ''' if task_vars is None: task_vars = self._job_vars async_jid = result.get('ansible_job_id') if async_jid is None: return dict(failed=True, msg="No job id was returned by the async task") # Create a new pseudo-task to run the async_status module, and run # that (with a sleep for "poll" seconds between each retry) until the # async time limit is exceeded. async_task = Task().load(dict(action='async_status jid=%s' % async_jid, environment=self._task.environment)) # FIXME: this is no longer the case, normal takes care of all, see if this can just be generalized # Because this is an async task, the action handler is async. However, # we need the 'normal' action handler for the status check, so get it # now via the action_loader normal_handler = self._shared_loader_obj.action_loader.get( 'normal', task=async_task, connection=self._connection, play_context=self._play_context, loader=self._loader, templar=templar, shared_loader_obj=self._shared_loader_obj, ) time_left = self._task.async_val while time_left > 0: time.sleep(self._task.poll) try: async_result = normal_handler.run(task_vars=task_vars) # We do not bail out of the loop in cases where the failure # is associated with a parsing error. The async_runner can # have issues which result in a half-written/unparseable result # file on disk, which manifests to the user as a timeout happening # before it's time to timeout. if (int(async_result.get('finished', 0)) == 1 or ('failed' in async_result and async_result.get('_ansible_parsed', False)) or 'skipped' in async_result): break except Exception as e: # Connections can raise exceptions during polling (eg, network bounce, reboot); these should be non-fatal. # On an exception, call the connection's reset method if it has one # (eg, drop/recreate WinRM connection; some reused connections are in a broken state) display.vvvv("Exception during async poll, retrying... (%s)" % to_text(e)) display.debug("Async poll exception was:\n%s" % to_text(traceback.format_exc())) try: normal_handler._connection._reset() except AttributeError: pass # Little hack to raise the exception if we've exhausted the timeout period time_left -= self._task.poll if time_left <= 0: raise else: time_left -= self._task.poll if int(async_result.get('finished', 0)) != 1: if async_result.get('_ansible_parsed'): return dict(failed=True, msg="async task did not complete within the requested time") else: return dict(failed=True, msg="async task produced unparseable results", async_result=async_result) else: return async_result
def run(self, tmp=None, task_vars=None): if self._play_context.connection != 'local': return dict( failed=True, msg='invalid connection specified, expected connection=local, ' 'got %s' % self._play_context.connection) provider = self.load_provider() transport = provider['transport'] or 'cli' display.vvvv('connection transport is %s' % transport, self._play_context.remote_addr) if transport == 'cli': pc = copy.deepcopy(self._play_context) pc.connection = 'network_cli' pc.network_os = 'eos' pc.remote_user = provider[ 'username'] or self._play_context.connection_user pc.password = provider[ 'password'] or self._play_context.password or 22 pc.privateip_key_file = provider[ 'ssh_keyfile'] or self._play_context.private_key_file pc.timeout = provider['timeout'] or self._play_context.timeout pc.become = provider['authorize'] or False pc.become_pass = provider['auth_pass'] connection = self._shared_loader_obj.connection_loader.get( 'persistent', pc, sys.stdin) socket_path = self._get_socket_path(pc) display.vvvv('socket_path: %s' % socket_path, pc.remote_addr) if not os.path.exists(socket_path): # start the connection if it isn't started display.vvvv('calling open_shell()', pc.remote_addr) rc, out, err = connection.exec_command('open_shell()') if not rc == 0: return {'failed': True, 'msg': 'unable to open shell'} else: # make sure we are in the right cli context which should be # enable mode and not config module rc, out, err = connection.exec_command('prompt()') while str(out).strip().endswith(')#'): display.debug('wrong context, sending exit to device', self._play_context.remote_addr) connection.exec_command('exit') rc, out, err = connection.exec_command('prompt()') task_vars['ansible_socket'] = socket_path else: provider_arg = { 'host': provider.get('host') or self._play_context.remote_addr, 'port': provider.get('port'), 'username': provider.get('username') or self._play_context.connection_user, 'password': provider.get('password') or self._play_context.password, 'authorize': provider.get('authorize') or False, 'auth_pass': provider.get('auth_pass'), 'timeout': provider.get('timeout') or self._play_context.timeout, 'use_ssl': task_vars.get('eapi_use_ssl') or False, 'validate_certs': task_vars.get('eapi_validate_certs') or True } self._task.args['provider'] = provider_arg if self._play_context.become_method == 'enable': self._play_context.become = False self._play_context.become_method = None return super(ActionModule, self).run(tmp, task_vars)