Hi,

I'm currently using the community.aws.aws_ssm connection plugin. It seems 
quite slow. I think it's initiating a new connection to the target machine 
for each file transfer or command execution. I was expecting Ansible to 
only create one session per host per play. I want to speed it up by 
re-using the session across all tasks in the play (per host). 

I'm assuming this is a development problem (i.e. I have to submit a pull 
request for aws_ssm) not a usage problem. Hence why I'm emailing the 
development list. If it is a usage problem, I'm happy to move this to 
another mailing list.

I can see documentation about ControlMaster and other options specific to 
SSH, to be passed to the SSH client. Those don't seem generalisable to 
other protocols.

The aws_ssm module itself already has _connect(), exec_command() and 
close(). So it seems like it's already structured in the right way. But I 
can see from running `-vvvv` and adding print statements to Ansible itself 
that Ansible core is calling _connect() and close() multiple times per task.

Is there an easy way to make Ansible re-use the Connection object? (e.g. 
add a property to the aws_ssm connection class. Or subclass it from 
something else.) Is this what "persistent" connections are?

There is ansible.netcommon.persistent connection 
<https://docs.ansible.com/ansible/latest/collections/ansible/netcommon/persistent_connection.html#ansible-collections-ansible-netcommon-persistent-connection>.
 
"This is a helper plugin to allow making other connections persistent." 
That sounds like what I want. But how do I use it? There's no other 
documentation about what that plugin does or how to use it, other than 
specific arguments.

The general Connection plugins documentation 
<https://docs.ansible.com/ansible/latest/plugins/connection.html> says 
"only one can be used per host at a time". I don't understand how the 
persistent plugin can help other plugins if only one plugin can be used at 
a time. Is the persistent plugin one that shouldn't be used by the end 
user, but rather it's an internal library that should be subclassed when 
implementing other connection plugins? Looking at the code of the 
persistent plugin, it sounds like it's actually a plugin for using sockets 
instead of other transport. So I'm not sure why it's called persistent.py 
instead of socket.py. Am I supposed to modify aws_ssm.py to create a socket 
and somehow pass that to the persistent plugin?

aws_ssm currently subclasses ansible.plugins.connection.ConnectionBase (here 
<https://github.com/ansible-collections/community.aws/blob/e80bf933412ea5c7ab2a94af945170cb2ebd900f/plugins/connection/aws_ssm.py#L351>).
 
That comes from connection/__init__.py 
<https://github.com/ansible/ansible/blob/devel/lib/ansible/plugins/connection/__init__.py>,
 
which also has a NetworkConnectionBase class. I tried modifying aws_ssm to 
subclass from this instead of ConnectionBase. This gives me an error when 
running:

Unexpected failure during module execution: 'Requested entry (plugin_type: 
connection plugin: my_better_ssm setting: persistent_log_messages ) was not 
defined in configuration.'

After looking at how grpc is implemented (ssm is not related to grpc. I 
just wanted an example that wasn't SSH), I added the following to the 
docstring:

extends_documentation_fragment:
  - ansible.netcommon.connection_persistent

Now I get:

Unexpected failure during module execution: 'Connection' object has no 
attribute 'nonetype'

I've added some more print statements to see what's going on. Ansible core 
is calling __getattr__ of the connector with name="nonetype" (as a string, 
not actually NoneType or None). 


I'm trying to see what's calling this. With epdb I see that the traceback 
at the point the exception is thrown is:

  /Users/matthew/.pyenv/versions/3.10.0/bin/ansible-playbook(8)<module>()
-> sys.exit(main())
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/cli/playbook.py(227)main()
-> PlaybookCLI.cli_executor(args)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/cli/__init__.py(647)cli_executor()
-> exit_code = cli.run()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/cli/playbook.py(143)run()
-> results = pbex.run()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/playbook_executor.py(190)run()
-> result = self._tqm.run(play=play)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/task_queue_manager.py(333)run()
-> play_return = strategy.run(iterator, play_context)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/plugins/strategy/linear.py(243)run()
-> self._queue_task(host, task, task_vars, play_context)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/plugins/strategy/__init__.py(391)_queue_task()
-> worker_prc.start()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/process/worker.py(93)start()
-> return super(WorkerProcess, self).start()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/multiprocessing/process.py(121)start()
-> self._popen = self._Popen(self)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/multiprocessing/context.py(277)_Popen()
-> return Popen(process_obj)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/multiprocessing/popen_fork.py(19)__init__()
-> self._launch(process_obj)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/multiprocessing/popen_fork.py(71)_launch()
-> code = process_obj._bootstrap(parent_sentinel=child_r)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/multiprocessing/process.py(315)_bootstrap()
-> self.run()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/process/worker.py(126)run()
-> return self._run()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/process/worker.py(170)_run()
-> ).run()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/task_executor.py(158)run()
-> res = self._execute()
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/task_executor.py(560)_execute()
-> plugin_vars = self._set_connection_options(cvars, templar)
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/task_executor.py(1087)_set_connection_options()
-> varnames.extend(self._set_plugin_options(plugin_type, variables, 
templar, task_keys))
  
/Users/matthew/.pyenv/versions/3.10.0/lib/python3.10/site-packages/ansible/executor/task_executor.py(1005)_set_plugin_options()
-> plugin = getattr(self._connection, '_%s' % plugin_type)
> 
/Users/matthew/Documents/mms/fastssm/connection_plugins/my_better_ssm.py(488)__getattr__()
-> return super().__getattr__(name)

 It looks like the "nonetype" thing comes from somewhere here 
<https://github.com/ansible/ansible/blob/devel/lib/ansible/executor/task_executor.py#L1100-L1104>
:

# deals with networking sub_plugins (network_cli/httpapi/netconf)
sub = getattr(self._connection, '_sub_plugin', None)
if sub is not None and sub.get('type') != 'external':
    plugin_type = get_plugin_class(sub.get("obj"))

My hunch is that I need to specify some config in ansible.cfg, or the host 
vars, or the docstring up the top of the aws_ssm.py file.But if there's a 
missing property somewhere, I would expect a KeyError about the property 
itself, not something related to "nonetype" as a string.

I also think the error is related to _sub_plugin={}. I can see that grpc.py 
sets something for that, and references a "subplugin" folder. I've never 
heard of sub plugins before. I'm not sure if that's a red herring, or if 
I'm supposed to put an object containing the low level connection inside 
that.

I'm quite lost now. How do I get Ansible to only call _connect once per 
host per play?

Regards,
Matt

-- 
You received this message because you are subscribed to the Google Groups 
"Ansible Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to ansible-devel+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/ansible-devel/2f8d72e0-c5e9-421a-a0ec-78980ed7c747n%40googlegroups.com.

Reply via email to